在模板haskell中运行模板haskell

时间:2014-04-12 02:04:52

标签: haskell template-haskell acid-state

insertST :: StateDecoder -> SomeState -> Update SomeState SomeThing
insertST stDecoder st = ...

StateDecoder中的东西不能用在

$(makeAcidic ''SomeState ['insertST])

但如果我声明一个状态并将其包装成这样......

myDecoder :: StateDecoder 
myDecoder = ...

insertSomeState :: SomeState -> Update SomeState SomeThing
insertSomeState st = insertST someDecoder

然后它可以工作

我有很多数据类型遵循这种模式,所以我想我会写一些TH来解决它。

mkWrappedAcid :: Name -> Name -> Q [Dec] 
mkWrappedAcid decoder stname = do 
    insP@(FunD n _) <- insertMaker decoder stname  
    acidP <- mkAcidic stname [n]
    return $[insP] ++ acidP

insertMaker :: Name -> Name -> Q [Dec]
insertMaker decoder stname = (funD istorename) [(clause [] (normalB insertStTH ) [] )
 where 
    istorename = mkName.concat $ ["insert" , (nameBase stname)]
    insertStTH = appE (varE 'insertST ) (varE decoder)

哪一个都很漂亮,但是当我试着跑...

$(mkWrappedAcid 'myDecoder ''SomeState) 

我明白了......

    `insertSomeState' is not in scope at a reify

我知道它与模板haskell中的登台问题有关,但我不知道如何解决它。如果我这样做就行了

$(mkWrappedAcid 'myDecoder ''SomeState)
$(makeAcidic ''SomeState ['insertSomeState]) 

但这没有用!

1 个答案:

答案 0 :(得分:1)

我认为user2407038是正确的,不可能直接执行此操作,我最终使用的一种解决方法是从创建它们的例程中提取命名函数的例程。然后你可以构建一个新的模板haskell片段,可以在同一个模块中创建第一个片段之后调用...我的方式是这样的。

mkWrappedAcid :: Name -> Name -> Q [Dec] 
mkWrappedAcid decoder stname = do 
    insP@(FunD n _) <- insertMaker decoder stname  
    acidP <- mkAcidic stname [n]
    return $[insP] ++ acidP

insertMaker :: Name -> Name -> Q [Dec]
insertMaker decoder stname = (funD istorename) [(clause [] (normalB insertStTH ) [] )
 where 
    istorename = mkName.concat $ ["insert" , (nameBase stname)]
    insertStTH = appE (varE 'insertST ) (varE decoder)

变成......

mkWrappedAcid :: Name -> Name -> Q [Dec] 
mkWrappedAcid decoder stname = do 
  (Loc _ _ md _ _) <- location
  makeAcidic storename (acidPathMaker md storename)

insertMaker :: Name -> Name -> Q [Dec]
insertMaker decoder stname = (funD istorename) [(clause [] (normalB insertStTH ) [])] 
 where 
    insertStTH = appE (varE 'insertST ) (varE decoder)

istorename = mkName.concat $ ["insert" , (nameBase stname)]

acidPathMaker md storename = [modulePlusIname]
  where 
     inameString = nameBase (istorename storename)
     modulePlusIname = mkName . concat $ [md , ".", inameString]

通过这种分离,您可以创建包裹的酸状态,如......

$(acidPathMaker 'myDecoder ''SomeState)
$(mkWrappedAcid ''SomeState )

哪个对我好。