使用Template Haskell自动声明yesod处理程序

时间:2015-01-17 22:09:16

标签: haskell yesod template-haskell

例如,我在Model

中有下一个实体类型
User json
    username Text

并遵循Haskell类型:

Entity User

删除用户的处理程序:

路由文件:

/users/#UserId UserR DELETE

处理程序声明:

deleteUserR :: UserId -> Handler Value
deleteUserR uid = do
    runDB $ delete uid
    sendResponseStatus status200 ("DELETED" :: Text)

我想写这样的模板函数:

mkDeleteHandler :: String -> Q [Dec]
mkDeleteHandler name = do
    [d|hname idname = do
        runDB $ delete idname
        sendResponseStatus status200 ("DELETED" :: Text)|]
        where hname  = mkName ("delete" ++ name ++ "R")
              idname = mkName ("i" ++ name)

在我的Handler.User模块中,我写了

mkDeleteHandler "User"

但它不起作用。编译器写下一个警告:

警告:已定义但未使用:hname

警告:已定义但未使用:idname

错误:

不在范围内:deleteUserR

1 个答案:

答案 0 :(得分:1)

编辑:添加了简单类型签名参数化示例

我认为mkDeleteHandler中的功能名称绑定存在问题。我会尝试这样的例子(示例简化):

mkHandler :: String -> String -> Q [Dec]
mkHandler typeName funcName = do
  funDecl <- [d| funcName :: String -> IO()
                 funcName var1 = do
                 print var1 |]

  let [SigD _ (AppT _ t0), FunD _ funBody] = funDecl
      sigBody' = (AppT (AppT ArrowT (ConT tname)) t0)

  return $ [SigD hname sigBody', FunD hname funBody]

  where
    hname  = mkName funcName
    tname = mkName typeName

然后你可以拼接它:

data Foo = Foo Int
     deriving Show

$(mkHandler "Int" "handlerInt")
$(mkHandler "String" "handlerString")
$(mkHandler "Foo" "handlerFoo")

main = do
  handlerInt 5
  handlerString "Hello World"
  handlerFoo $ Foo 5

请注意,mkHandler应在单独的模块中定义,并在使用前先导入。

你的问题是根本没有使用hname,就像编译器已正确警告一样。解决方法是我们生成一个&#34;模板&#34;使用引号括起来的函数声明,然后用我们自己的hname替换生成的函数名。

恕我直言,学习Template Haskell的最佳教程是this one