Ошибка ввода при использовании Snaplet-сессии - PullRequest
1 голос
/ 12 декабря 2011

Тип приложения

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'

Ответы [ 2 ]

3 голосов
/ 12 декабря 2011

Вы должны связать свой SessionManager с контекстом обработчика, прежде чем вы сможете использовать функции, которые работают с ним. Это делается с помощью:

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

Если вы также хотите зафиксировать свой сеанс впоследствии (поскольку вы изменили сеанс и не просто прочитали переменную), вам необходимо:

withSession . withTop session $ ...

Если вы добавите следующий фрагмент кода в код инициализации снэплета вашего основного приложения, вам вообще не придется беспокоиться о фиксации сеансов, потому что это делается автоматически для вас:

wrapHandlers withSession
0 голосов
/ 19 декабря 2011

Одним из способов решения проблемы является следующая строка:

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

Другая вещь, которую я считаю полезной, - это специализация сигнатур типов для моего приложения.В этом случае подпись нового типа будет выглядеть следующим образом:

companyHandler :: Handler App App ()

Большую часть времени вы не будете писать универсальный код, который следует многократно использовать в нескольких приложениях, поэтому небольшая потеря общности здесь несделаю тебе больноНаличие более конкретных сигнатур типов обычно упрощает расшифровку сообщений об ошибках, что может помочь при компиляции кода.Даже когда я пишу код, который должен быть универсальным для всех приложений / снэплетов, иногда мне все же полезно начинать с более конкретного типа, а затем обобщать после того, как я его заработаю.

Что dflemstr сказал о withSessionправильный.Обычно я предпочитаю делать с Session один раз вокруг всего, а не помещать его в вызов setInSession, но вы должны делать все, что подходит для вашего приложения.

...