2
votes

I was playing with the Reader monad in Purescript and I encountered a weird behaviour. I don't know if it's because my lack of comprehension of this monad or if I'm missing something else.

This is my code :

type Level = Number
type Doc = Reader Level String

renderLine :: String -> Level -> String
renderLine s 0 = s
renderLine s l = "\t" ++ (renderLine s (l - 1))

line :: String -> Doc
line s = do
    level <- ask
    return (renderLine s level)

This is okay and will compile. Nevertheless, before this I tried something simpler in my function line like this :

line :: String -> Doc
line s = do
    level <- ask
    return "Hello Reader monad"

And it won't compile, despite the fact that (renderLine s level) and "Hello Reader monad" has the same type. It will throw me this error : "No instance found for Control.Monad.Reader.Class.MonadReader u14555 (Control.Monad.Reader.Trans.ReaderT Prim.Number Control.Monad.Identity.Identity)"

I'm sure I'm missing something, but I don't know what.

1

1 Answers

7
votes

A more readable version of that error would be:

No instance found for MonadReader ? (Reader Number)

I think the problem here is due to the lack of functional dependencies in PureScript - in Haskell the MonadReader class is defined as MonadReader r m | m -> r so r is decided by m, but we can't do that in PureScript.

I suspect the reason it works in the former case rather than the latter is type of level is being unified with Level in the call to renderLine, which means r must therefore also be Level.

As you're not doing anything with level in the latter case, the type variable is left un-unified, and that's where the error comes from as there is indeed no instance for MonadReader when r is unknown.