代码之家  ›  专栏  ›  技术社区  ›  Matt Ahrens

使用TH类注释中的数据类型生成类型注释

  •  2
  • Matt Ahrens  · 技术社区  · 7 年前

    在使用模板haskell的haskell项目中,我试图生成一个表达式,该表达式的类型注释为幻影类型。

    一个简单的例子是 DataKinds KindSignatures 例如:

    {-# LANGUAGE DataKinds, KindSignatures #-}
    data Foo = A | B
    data GenMe (w :: Foo) = GenMe Int
    
    [| $(generate some code) :: GenMe $(genType someCompileTimeData) |]
    

    genType 因此

    genType :: Foo -> Q Type
    

    提升只是提升保存编译时的变量 Foo 价值我不知道从 Type Data Constructors

    有什么想法吗?谢谢

    1 回复  |  直到 7 年前
        1
  •  1
  •   Alec    7 年前

    分割此问题的另一种方法是定义 promote :: Exp -> Maybe Type 函数,然后使用 lift 在…上 Foo .

    -- | Takes the AST for an expression and tries to produce the corresponding
    -- promoted type AST.
    promote :: Exp -> Q Type
    promote (VarE n) = fail ("Cannot promote variable " ++ show n)
    promote (ConE n) = pure (PromotedT n)
    promote (LitE l) = LitT <$> promoteLit l
    promote (TupE es) = foldl AppT (PromotedTupleT (length es)) <$> (traverse promote es)
    promote (ListE es) = foldr (\x xs -> AppT (AppT PromotedConsT x) xs) PromotedNilT <$> (traverse promote es)
    promote (ParensE e) = ParensT <$> promote e
    promote (AppE e1 e2) = AppT <$> promote e1 <*> promote e2
    promote (InfixE (Just e1) e2 (Just e3)) = AppT <$> (AppT <$> promote e2 <*> promote e1) <*> promote e3
    promote _ = fail "Either impossible to promote or unimplemented"
    
    -- | Promote an expression literal to a type one
    promoteLit :: Lit -> Q TyLit
    promoteLit (StringL s) = pure (StrTyLit s)
    promoteLit (IntegerL i) = pure (NumTyLit i)
    promoteLit _ = fail "Expression literal cannot be promoted"
    

    然后,我认为以下几点应该行得通

    ghci> :set -XDeriveLift -XDataKinds -XKindSignatures -XTemplateHaskell -XQuasiQuotes
    ghci> data Foo = A | B deriving (Lift)
    ghci> foo1 = A
    ghci> data GenMe (w :: Foo) = GenMe Int
    ghci> runQ [| GenMe 1 :: GenMe $(promote =<< lift foo1) |]
    SigE (AppE (ConE Ghci5.GenMe) (LitE (IntegerL 1))) (AppT (ConT Ghci5.GenMe) (PromotedT Ghci3.A))