gpt4 book ai didi

haskell - 在 TemplateHaskell 中使用列表

转载 作者:行者123 更新时间:2023-12-04 21:18:56 24 4
gpt4 key购买 nike

Here's the tutorial I'm working from .

他有一个例子,tupleReplicate ,它返回一个函数,该函数接受一个值并复制它:

tupleReplicate :: Int -> Q Exp
tupleReplicate n = do id <- newName "x"
return $ LamE (VarP id)
(TupE $ replicate n $ VarE id)

所以 VarE id返回一个表达式,然后可以与 replicate 一起使用?我的问题是,如果 id 这将如何工作是一个 list ?我想做类似的事情:
let vals = mkName "vals"
LamE (ListP vals) (map reverse $ ListE vals)

除了这不起作用,因为 ListE返回 Exp ,不是 [Exp] .

更一般地说,我想在 TemplateHaskell 中编写一个接受列表并将函数应用于它的函数。

有一些示例代码 here ,我正在尝试编写一个函数,如
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 表达式(下面的翻译):
LamE [ListP [VarP id,VarP name]] (AppE (AppE (ConE Person) (AppE (VarE fromSql) (VarE id))) (AppE (VarE fromSql) (VarE name)))
\ [ id, name ] -> ( ( Person ( fromSql id )) ( fromSql name ))
\ [ id, name ] -> Person $ fromSql id $ fromSql name

(我不会说流利的 Exp ,我在 ghci 中说的是 runQ [| \[id,name] -> Person (fromSql id) (fromSql name) |]!)

我选择使用字符串来定义标识符 idname ,因为您可以从表中读取它,但您也可以生成名为 field_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

行动在 ghci -XTemplateHaskell :
*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"

请注意我们如何使用 newName 创建的标识符有序列号使它们独一无二,而我们传入的序列号前面有一个破折号, 'fromSql'Person保留为它们的实际定义。

如果您不想使用 lambda 表达式,则可以使用
runQ [d| makeModel [id,name] = Person (fromSql id) (fromSql name) |]

作为您的起点 - [d| ... |]用于函数定义。

关于haskell - 在 TemplateHaskell 中使用列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16291032/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com