使用模板 Haskell 自动声明 yesod 处理程序
Automatically declaration yesod handlers using Template Haskell
例如,我在模型中有下一个实体类型
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
编辑:添加了简单类型签名参数化示例
我认为您的 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
,正如编译器已正确警告的那样。解决方法是我们使用引号括号生成一个 "template" 函数声明,然后将生成的函数名称替换为我们自己的 hname
.
恕我直言,学习 Template Haskell
的最佳教程是 this one。
例如,我在模型中有下一个实体类型
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
编辑:添加了简单类型签名参数化示例
我认为您的 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
,正如编译器已正确警告的那样。解决方法是我们使用引号括号生成一个 "template" 函数声明,然后将生成的函数名称替换为我们自己的 hname
.
恕我直言,学习 Template Haskell
的最佳教程是 this one。