【问题标题】:Automatically declaration yesod handlers using Template Haskell使用 Template Haskell 自动声明 yesod 处理程序
【发布时间】:2015-03-16 07:02:17
【问题描述】:

例如,我在模型中有下一个实体类型

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

【问题讨论】:

    标签: haskell yesod template-haskell


    【解决方案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,就像编译器已正确警告一样。解决方法是我们使用引号生成一个“模板”函数声明,然后将生成的函数名称替换为我们自己的hname

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

    【讨论】:

    • 函数声明 deleteUserR 现在存在于模块 Handler.User 中,但是当 Yesod 运行器尝试从模块 Application 调用 deleteUserR 时,编译器写入 Yesod 特定错误:由于使用 @987654329 而导致 (ToTypedContent res0) 没有实例@res0' 不明确
    • 嗨,也许我们应该在生成的函数声明中添加类型签名。我已经更新了答案中的代码示例。用正确的类型签名再试一次,在你的情况下:funcName :: UserId -&gt; Handler Value
    • 问题:我不知道funcName 的类型签名它的类型是这样的:Key User -&gt; Handler Value 但类型 User 是 mkDeleteHandler 的参数,其中Key User = UserId
    • 嗯,如果没有看到完整的代码,我不知道你到底想做什么......你能用完整的代码更新你的问题吗?
    • 您是否安装了 yesod 软件包?例如,默认 Yesod 脚手架站点足以出错
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-03
    • 1970-01-01
    • 2018-09-16
    • 2023-03-26
    相关资源
    最近更新 更多