【问题标题】:Type error using snaplet-session使用 snaplet-session 输入错误
【发布时间】:2011-12-20 01:08:12
【问题描述】:

应用类型

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'

【问题讨论】:

    标签: haskell haskell-snap-framework


    【解决方案1】:

    您必须将SessionManager 绑定到处理程序的上下文,然后才能使用对其进行操作的函数。这是通过以下方式完成的:

    withTop session $ setInSession "name" (convert mname)
    -- Where session is the generated lens for your snaplet
    

    如果您还想在之后提交会话(因为您更改了会话并且不只是读取变量),您需要:

    withSession . withTop session $ ...
    

    如果您将以下代码添加到主应用程序的 snaplet 初始化代码中,您根本不必担心提交会话,因为它会自动为您完成:

    wrapHandlers withSession
    

    【讨论】:

    • 它不起作用。 withSession session $ setInSession "name" (convert mname) :: Handler b SessionManager (),代表setInSession :: Text -&gt; Text -&gt; Handler b SessionManager ()
    • 对不起,我没有测试我应该做的代码。似乎会话 API 的构造方式很奇怪;您需要使用withTop 而不是withSession。如果您执行withSession . withTop session $ ...,它将为您做的是在您完成会话后提交会话。
    • 它可以编译,但请求之间不共享会话。完整代码为here using withhere using withSession and withTop
    • 问题不在于会话管理系统,而在于您测试它的方式。见your other question
    • 谢谢,现在可以使用了。最后一个问题是commit session 做什么?我发现使用和不使用没有区别。
    【解决方案2】:

    解决问题的一种方法是使用以下行:

    companyHandler = with session $ method GET getter <|> method POST setter
    

    我觉得有帮助的另一件事是将类型签名专门用于我的应用程序。在这种情况下,新的类型签名将是:

    companyHandler :: Handler App App ()
    

    大多数情况下,您不会编写应该可在多个应用程序中重复使用的通用代码,因此这里的小幅通用性损失不会对您造成伤害。拥有更具体的类型签名通常会使错误消息更容易破译,这对编译代码有很大帮助。即使我编写的代码应该在所有应用程序/snaplet 中通用,有时我仍然发现从更具体的类型开始,然后在我得到它工作后进行概括是有帮助的。

    dflemstr 关于 withSession 的说法是正确的。我通常更喜欢在所有事情上都使用一次 withSession,而不是把它放在对 setInSession 的调用上,但是你应该做任何适合你的应用程序的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-29
      • 1970-01-01
      • 2014-05-19
      • 1970-01-01
      • 2011-05-01
      • 2020-11-06
      • 2012-04-13
      • 2014-10-12
      相关资源
      最近更新 更多