6
votes

I am looking at the documentation for the Reader monad and ReaderT monad transformer.

The relevant definitions are:

newtype ReaderT k r m a :: forall k. * -> (k -> *) -> k -> *
type Reader r = ReaderT * r Identity

I don't understand what the * are doing in the definitions. In particular I am attempting to derive a new monad from ReaderT with IO as the base monad and a class constraint on the r value.

I am not sure why there is a fourth input to ReaderT (k) and what Reader is doing with that value when it puts a * in that position.

1
Note that the source code for ReaderT is newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }. The k is only generated in the documentation by Haddock to emphasize the poly-kindedness of ReaderT (-XPolyKinds is enabled in the module where it is defined).Alec
"I am attempting to derive a new monad from ReaderT with IO as the base monad and a class constraint on the r value" - while this is likely to cause more problems than it solves (the placing of a constraint on the r value, not the derivation of a new type from ReaderT with m instantiated to IO) I don't see why doing this would be impeded by the polykinded definition of ReaderT. As @Alec states, the k parameter is an artifact of haddock - in reality, it is entirely implicit, and you can pretend that ReaderT :: (* -> *) -> * -> * (because it does indeed have that type).user2407038
@user2407038 and nicolas You are both correct. The constraint belonged and is now placed on an instance declaration not the monad definition.John F. Miller
@Alec, I think this is the real answer to my question. (Make it an answer instread of a comment and I'll accept it.) As a follow up where did the type constructor and the field name disappear to in the documentation. Those are useful to know.John F. Miller
@JohnF.Miller I can see both the constructor and field name here. Where do you find that it is omitted? (If you do not see it there, you should - I can only guess that there is something strange going on with your browser).user2407038

1 Answers

5
votes

* is the kind of types with values : it stands for things like Int, List Int etc..

forall k means k is not necessarily of that kind. it stands for any kind of types, viewed as simply static things which you can declare and manipulate, but are not necessarily associated with runtime values. One example of this is when you want to 'decorate' some other type with extra information : the embroidering type has no reason to have any sort of value attached to it, it is "pure" information, to some embroided type (which usually have values)

More simply here, you can see that in Reader it all gets specialized to *, and m is specialised to the Identity monad. That's where you'd want your IO monad to be.

As for the constraints, it is best to not specify it in the type itself. Upon usage, where you use a particular method attached to the typeclass, it will get added on the fly. Indeed there are no reason expressions written which do not use a method should be burdened by requiring their callers to provide it.

(Unless you have a very good reason to, for deducing other instances, as in Dict where you capture a typeclass witness as a runtime value with a GADT, but that's probably not what you want to do)