Как добавить монаду Reader в монаду Скотти?

Я пытаюсь использовать Скотти для создания очень простого API. Я хотел бы расширить монады Скотти, чтобы мои действия обработчика маршрута могли получить доступ к неизменной среде. Я считаю, что это можно сделать, добавив в стек монаду Reader. Пока я просто хочу передать некоторые Text данные.

Я расширил монады Скотти следующим образом:

type BrandyScottyM = ScottyT TL.Text (ReaderT T.Text IO)
type BrandyActionM = ActionT TL.Text (ReaderT T.Text IO)

https://github.com/stu-smith/Brandy/blob/0838a63537d7e396ac82d58d460c6529349303d3/src/Core.hs

Итак, мой первый вопрос: правильный ли это подход?

Я успешно изменил типы своих обработчиков маршрутов, но не могу понять, как запустить Скотти, используя этот стек. Я пробовал следующее:

runScotty :: Port -> Text -> BrandyScottyM () -> IO ()
runScotty port file = T.scottyT port ((\f -> runReader f file)) id

https://github.com/stu-smith/Brandy/blob/0838a63537d7e396ac82d58d460c6529349303d3/src/Main.hs

Но я получаю сообщение об ошибке:

  Couldn't match type `IO' with `Data.Functor.Identity.Identity'
    Expected type: Reader Text (IO a)
      Actual type: ReaderT Text IO a
    In the first argument of `runReader', namely `f'
    In the expression: runReader f file
    In the second argument of `T.scottyT', namely
      `((\ f -> runReader f file))'
/home/stu/git/Brandy/src/Main.hs: line 36, column 65:
  Couldn't match type `ReaderT Text IO Network.Wai.Internal.Response'
                  with `IO Network.Wai.Internal.Response'
    Expected type: ReaderT Text IO Network.Wai.Internal.Response
                   -> IO Network.Wai.Internal.Response
      Actual type: ReaderT Text IO Network.Wai.Internal.Response
                   -> ReaderT Text IO Network.Wai.Internal.Response
    In the third argument of `T.scottyT', namely `id'
    In the expression: T.scottyT port ((\ f -> runReader f file)) id
    In an equation for `runScotty':
        runScotty port file = T.scottyT port ((\ f -> runReader f file)) id

Итак, мой второй вопрос: как мне запустить Скотти с другим стеком монад? Это моя первая попытка использовать преобразователи монад, и я, кажется, безнадежно заблудился.


person stusmith    schedule 14.04.2014    source источник


Ответы (1)


Ваш подход выглядит нормально. Ошибка типа связана с тем, что вы должны использовать runReaderT, а не runReader (runReader используется только тогда, когда вы используете Reader, который является ReaderT только с фиктивной монадой Identity под ней).

person duplode    schedule 14.04.2014
comment
Ага, здорово, что я попал в нужное русло. Мне также пришлось сделать Reader как на уровне приложения, так и на уровне действий: так что последний вызов: T.scottyT port (`runReaderT` file) (`runReaderT` file) - person stusmith; 15.04.2014