Type error using snaplet-session

耗尽温柔 提交于 2019-12-13 01:00:16

问题


The App type

data App = App
    { _heist       :: Snaplet (Heist App)
    , _session     :: Snaplet SessionManager
    }

The initializer

...
addRoutes [ ("/ss", companyHandler)
          , ("", heistServe)
          ]
...

The handler

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")

The heistServe has type Handler b (Heist b) ()

Type error:

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'

回答1:


You have to bind your SessionManager to the context of the handler before you can use functions that operate on it. This is done with:

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

If you also want to commit your session afterwards (because you altered the session and didn't just read a variable), you need to:

withSession . withTop session $ ...

If you add the following piece of code to your main application's snaplet initialization code, you don't have to worry about committing sessions at all, because it is done automatically for you:

wrapHandlers withSession



回答2:


One way to solve the problem is with the following line:

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

Another thing I find helpful is to specialize the type signatures to my application. In this case, the new type signature would be:

companyHandler :: Handler App App ()

Most of the time you won't be writing generic code that should be reusable across multiple apps, so the small loss of generality here doesn't hurt you. Having more concrete type signatures generally makes error messages easier to decipher, which can be a big help in getting your code compiling. Even when I am writing code that should be generic across all apps/snaplets, sometimes I still find it helpful to start with a more specific type and then generalize after I get it working.

What dflemstr said about withSession is correct. I typically prefer to do withSession once around everything as opposed to putting it on the call to setInSession, but you should do whatever is appropriate for your application.



来源:https://stackoverflow.com/questions/8475088/type-error-using-snaplet-session

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!