How do I add the Reader monad to Scotty's monad?
Asked Answered
I

1

7

I'm trying to use Scotty to build a very simple API. I'd like to extend the Scotty monads such that my route handler actions are able to access an unchanging environment. I believe the way to do this would be to add a Reader monad to the stack. For now I just want to pass some Text data around.

I've extended the Scotty monads as follows:

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

So my first question is, is this the correct approach?

I've successfully changed the types of my route handlers, but I can't work out how to launch Scotty using this stack. I've attempted the following:

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

But I get the error:

  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

So my second question is, how do I launch Scotty with a different monad stack? This is my first attempt at using monad transformers and I seem to be hopelessly lost.

Iorgo answered 14/4, 2014 at 20:56 Comment(0)
S
10

Your approach looks okay. The type error is because you should use runReaderT rather than runReader (runReader is only for when you use Reader, which is ReaderT with just the dummy Identity monad below it).

Slippy answered 14/4, 2014 at 21:5 Comment(1)
Aha fantastic that got me on the right lines. I also had to make the Reader at both the application and action levels: so the final call is: T.scottyT port (`runReaderT` file) (`runReaderT` file)Iorgo

© 2022 - 2024 — McMap. All rights reserved.