假设我有以下 Haskell 程序:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
data A = A Int Int
deriving (Show, Typeable, Data)
main = print (f (toConstr (A undefined undefined)))
f :: Constr -> A
f c = _
我想实现f
这样它的类型就是 Constr -> A
,因此它在功能上等同于 A 1 2
。但是,我不想使用实际的构造函数;我只被允许使用Constr
对于 A
,和gunfold
。实际上,我如何使用 gunfold
应用构造函数,同时为每个构造函数位置提供不同的参数?越简单/越高效越好。
这里有更多背景信息:http://comments.gmane.org/gmane.comp.lang.haskell.libraries/24594 (具体来说,请参阅 Michael Sloan 的评论。)本质上,我们正在生成代码来使用 Template Haskell 调用构造函数;但是,由于我们的基础是 Data
例如,在一天结束时,我们必须经历 Data
在有人使用虚拟构造函数的情况下获得正确的行为。
最佳答案
fromConstrM
源自gunfold
。
您可以将它与 State
一起使用,对构造函数的 Int
字段进行简单编号。
import Data.Maybe
import Control.Monad.Trans.State
numbered :: Data d => State Int d
numbered = fromMaybe (fail "numbered - don't know which constructor to use next") $ gcast $ do
i <- get
put (i + 1)
return i
f :: Constr -> A
f c = fst . runState (fromConstrM numbered c) $ 1
如果您知道构造函数的参数是什么,您可以将它们保存在状态列表中,并在使用时对每个参数进行强制转换。
import Data.Dynamic
fillArgs :: Data d => State [Dynamic] d
fillArgs = do
args <- get
case args of
[] -> fail "fillArgs - not enough arguments provided"
(x:xs) -> maybe
(fail "fillArgs - type mismatch")
(\x -> do
put xs
return x
)
(fromDynamic x)
applyConstr :: Data d => Constr -> [Dynamic] -> d
applyConstr c = fst . runState (fromConstrM fillArgs c)
f :: Constr -> A
f c = applyConstr c (map toDyn ([1..] :: [Int]))
关于haskell - 使用枪夹填充位置参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30058605/