Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
记录字段名为变量的模板Haskell?_Haskell_Template Haskell - Fatal编程技术网

记录字段名为变量的模板Haskell?

记录字段名为变量的模板Haskell?,haskell,template-haskell,Haskell,Template Haskell,我有下面一段实现monad的代码。稍后,我将尝试使用它简化具有更复杂逻辑的字段设置 data Rec = Rec { alpha :: Int, beta :: Double, } deriving (Show) defaultRec = Rec 0 0 0 data Record r = Record { runRecord :: Rec -> (Rec, r) } instance Monad Record where return r = Record $

我有下面一段实现monad的代码。稍后,我将尝试使用它简化具有更复杂逻辑的字段设置

data Rec = Rec {
    alpha :: Int,
    beta  :: Double,
} deriving (Show)
defaultRec = Rec 0 0 0

data Record r = Record { runRecord :: Rec -> (Rec, r) }
instance Monad Record where
    return r = Record $ \s -> (s, r)
    a >>= b  = Record $ \s -> let (q, r) = runRecord a s in runRecord (b r) q

createRecord f = fst $ runRecord f defaultRec

changeAlpha x  = Record $ \s -> (s { alpha = x }, ())
我将使用如下代码:

myRecord = createRecord (changeAlpha 9)
changeBeta x = $(makeChange beta) x
这段代码可以工作,但我想使用模板Haskell来简化changeAlpha函数。有这样的东西会很好:

myRecord = createRecord (changeAlpha 9)
changeBeta x = $(makeChange beta) x
现在,我已经做到了这一点:

changeBeta x = Record $ $([| \z -> \s -> (s { beta = z }, ()) |]) x
但一旦我把它改成这个:

changeBeta f x = Record $ $([| \z -> \s -> (s { f = z }, ()) |]) x
我明白了:

TestTH.hs:21:49: `f' is not a (visible) constructor field name

没有变化的工作。这可能吗?

我认为
f
只是一个名字;您需要“取消引用”它,因为它来自环境,而不仅仅是引号内的内容。我在这里找到了一个例子[,请参阅“10.1.1从元组中选择”]。unquote使用了
$
,所以我想您的最终代码应该是这样的

changeField f = [| \z s -> s { $(varE f) = z } |]

不幸的是,我的ghc版本(7.0.3)似乎在抱怨
$
。(它给出了一个解析错误。)希望这个问题能得到更多的关注,对我来说似乎不错(尽管可能会删除不相关的monad部分)。

问题是,您只能拼接类型、表达式或声明列表。记录字段标签不是这两种类型,因此您必须使用TH组合符生成类型为
Q Exp
的表达式,然后将其拼接,尽管您仍然可以对其余部分使用牛津括号:

makeChange :: Name -> Q Exp
makeChange x = [|
    \z -> Record $ \s -> ( $(recUpdE [| s |] [fieldExp x [| z |]]), () ) |]
要使用它,您必须引用要更改的字段的名称:

changeBeta :: Double -> Record ()
changeBeta x = $(makeChange 'beta) x

你不是在重新发明状态单子和镜头吗

有一个数据镜头模板代码,它为类型中以u开头的每个“记录”生成镜头。

不是
$([| x |])
只是
x
?i、 e.
$()
[| |]
立即相互抵消。因此,您的
changeBeta
的上一个工作版本就是
changeBeta x=Record$\s->(s{beta=z},())