在TemplateHaskell中使用列表
他有一个例子,在TemplateHaskell中使用列表,haskell,template-haskell,Haskell,Template Haskell,他有一个例子,tupleReplicate,它返回一个函数,该函数接受一个值并复制它: tupleReplicate :: Int -> Q Exp tupleReplicate n = do id <- newName "x" return $ LamE (VarP id) (TupE $ replicate n $ VarE id) 但这不起作用,因为ListE返
tupleReplicate
,它返回一个函数,该函数接受一个值并复制它:
tupleReplicate :: Int -> Q Exp
tupleReplicate n = do id <- newName "x"
return $ LamE (VarP id)
(TupE $ replicate n $ VarE id)
但这不起作用,因为ListE
返回Exp
,而不是[Exp]
更一般地说,我想在TemplateHaskell中编写一个接受列表并对其应用函数的函数
这里有一些示例代码,我正在尝试编写一个函数,如
makeModel (id_ : name_ : []) = Person (fromSql id_) (fromSql name_)
首先,让我们打开一些扩展:
{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}
import Language.Haskell.TH
现在,我将伪造一些数据类型和类,以保持与现实世界的低交互:
data Person = Person Int String deriving Show
class SQL a where
fromSql :: String -> a
instance SQL Int where fromSql = read
instance SQL String where fromSql = id -- This is why I needed FlexibleInstances
好的,现在我们需要决定要生成什么代码。根据您的示例,我们可以将makeModel定义为lambda表达式(下面的翻译):
(我不会说流利的Exp
,我在ghci中运行了runQ[|\[id,name]->Person(fromSql id)(fromSql name)|]
)
我选择使用字符串来定义标识符id
和name
,因为您可以从表中读取,但也可以生成名为field\u 1
的标识符
makeMakeModel qFieldNames qMapFunction qConstructor = -- ["id","name"] 'fromSql 'Person
LamE [ListP (map VarP qFieldNames)] -- \ [id,name]
$ foldl AppE (ConE qConstructor) -- Person
[AppE (VarE qMapFunction) (VarE name)|name <- qFieldNames]
-- $ id $ name
makeModel fieldNames mapFunction constructor = do
names <- mapM newName fieldNames
return $ makeMakeModel names mapFunction constructor
请注意,我们用newName
创建的标识符是如何获得序列号以使其唯一的,而我们在前面用破折号传递的那些标识符,'fromSql
和'Person
保留为它们的实际定义
如果不想使用lambda表达式,可以使用
runQ [d| makeModel [id,name] = Person (fromSql id) (fromSql name) |]
作为起点-
[d |…|]
用于函数定义。您希望生成的函数看起来像什么?tuplerplicate 3
扩展为\x->(x,x,x)
。对于列表,您希望TH扩展到什么?我正在将数据库行转换为对象。所以我得到一个数据库行作为列表:[SqlValue]
。现在我想把它转换成一个对象MyObject
接受6个值,我的列表中有6项。所以我想在TemplateHaskell中编写一个函数,给定这个列表,它将返回MyObject
@n.m.的一个实例:请看这里:哦,我想我找到了。您是否正在尝试生成类似于的代码,其中makeModel[id,name]=Person(fromSql id)(fromSql name)
?另请参见另一个示例。谢谢您!这很有帮助。
makeMakeModel qFieldNames qMapFunction qConstructor = -- ["id","name"] 'fromSql 'Person
LamE [ListP (map VarP qFieldNames)] -- \ [id,name]
$ foldl AppE (ConE qConstructor) -- Person
[AppE (VarE qMapFunction) (VarE name)|name <- qFieldNames]
-- $ id $ name
makeModel fieldNames mapFunction constructor = do
names <- mapM newName fieldNames
return $ makeMakeModel names mapFunction constructor
*Main> runQ $ makeModel ["id","name"] 'fromSql 'Person
LamE [ListP [VarP id_0,VarP name_1]] (AppE (AppE (ConE Main.Person) (AppE (VarE Main.fromSql) (VarE id_0))) (AppE (VarE Main.fromSql) (VarE name_1)))
*Main> $(makeModel ["id","name"] 'fromSql 'Person) ["1234","James"]
Person 1234 "James"
runQ [d| makeModel [id,name] = Person (fromSql id) (fromSql name) |]