应用类型
data App = App
{ _heist :: Snaplet (Heist App)
, _session :: Snaplet SessionManager
}
初始化程序
...
addRoutes [ ("/ss", companyHandler)
, ("", heistServe)
]
...
处理程序
companyHandler :: Handler b v ()
companyHandler = method GET getter <|> method POST setter
where
getter = do
value <- getFromSession "name"
writeText $ fromMaybe "nothing" value
setter = do
mname <- getParam "name"
setInSession "name" (convert mname)
getter
convert = T.pack . B.unpack . (fromMaybe "nothing")
heistServe
的类型为Handler b (Heist b) ()
输入错误:
src/Tutorial.hs:50:52:
Couldn't match type `v' with `SessionManager'
`v' is a rigid type variable bound by
the type signature for companyHandler :: Handler b v ()
at src/Tutorial.hs:50:1
Expected type: Handler b v ()
Actual type: Handler b SessionManager ()
In the second argument of `method', namely `setter'
In the second argument of `(<|>)', namely `method POST setter'
答案 0 :(得分:3)
您必须先将SessionManager
绑定到处理程序的上下文,然后才能使用对其进行操作的函数。这完成了:
withTop session $ setInSession "name" (convert mname)
-- Where session is the generated lens for your snaplet
如果您之后还想提交会话(因为您更改了会话并且不只是读取变量),您需要:
withSession . withTop session $ ...
如果将以下代码添加到主应用程序的snaplet初始化代码中,则根本不必担心提交会话,因为它是自动完成的:
wrapHandlers withSession
答案 1 :(得分:0)
解决问题的一种方法是使用以下行:
companyHandler = with session $ method GET getter <|> method POST setter
我觉得有用的另一件事是将类型签名专门化到我的应用程序。在这种情况下,新类型签名将是:
companyHandler :: Handler App App ()
大多数情况下,您不会编写应该可以在多个应用程序中重复使用的通用代码,因此这里的一般性缺失不会对您造成伤害。拥有更具体的类型签名通常会使错误消息更容易破译,这对于获取代码进行编译非常有帮助。即使我编写的代码在所有应用程序/快照中都应该是通用的,有时我仍然觉得从更具体的类型开始然后在我使用它之后进行概括是有帮助的。
dflemstr对theession所说的是正确的。我通常更倾向于对所有内容执行withSession而不是将其置于setInSession的调用上,但是你应该做适合你的应用程序的任何事情。