Запуск шаблона haskell в шаблоне haskell

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 ответ

Ну, я принимаю 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 )

Что просто прекрасно для меня.

Другие вопросы по тегам