Differing Reader Behaviour

42 views Asked by At

I'm writing a wrapper around a Warp server where users can specify routes and handlers to make a web server. I decided to try using Continuation Monads to allow handlers to exit using a continuation when a route matches. Here are the types and definitions I'm starting with:

import Control.Monad.Cont
import Control.Monad.Reader
import qualified Network.Wai as W
import qualified Data.Text as T

type App r a = ContT r (ReaderT W.Request IO) a
type Handler a = ReaderT W.Request IO a
type Respond = ((Status, T.Text) -> App (Status, T.Text) ())

route :: T.Text -> Handler (Status, T.Text) -> Respond -> App (Status, T.Text) ()
route routePath handler respond = do
  liftIO $ print $ "Checking" `T.append` routePath
  pth <- path
  when (routePath == pth) $ do
    req <- ask
    response <- liftIO $ runReaderT handler req
    respond response

An app is a collection of routes, each route reads the current continuation from the Reader environment; I originally wrote it like this:

hello :: Handler (Status, T.Text)
hello = return (ok200, "Hello World!")

goodbye :: Handler (Status, T.Text)
goodbye = return (ok200, "Goodbye World!")

app :: Respond -> App (Status, T.Text) ()
app = do
  route "/hello" hello
  route "/goodbye" goodbye

Strangely this doesn't seem to work, it only prints "Checking /goodbye"; however if we instead write the reader in the next form it works properly, as far as I was aware these two definitions should be equivalent; but apparently I'm missing something:

app :: Respond -> App (Status, T.Text) ()
app resp = do
  route "/hello" hello resp
  route "/goodbye" goodbye resp

Is there any way I can get the proper behaviour using the original app definition? Is there some way that the Reader Monad is messing up the continuations somehow?

I suspect that somehow the monad definition for reader is interrupting the order of computation; but it's not clear to me how:

instance Monad ((->) r) where
    f >>= k = \ r -> k (f r) r

Thanks!

0

There are 0 answers