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.
* is the kind of types with values. forall k means k is not necessarily of that kind.
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)