let bind (u: 'a reader) (f : 'a -> 'b reader) : 'b reader =
fun e -> (fun v -> f v e) (u e);;
-We've just beta-expanded the familiar `f (u e) e` into `(fun v -> f v e) (u e)`, in order to factor out the parts where any Reader monad is being supplied as an argument to another function. Then if we want instead to add a Reader layer to some arbitrary other monad M, with its own M.unit and M.bind, here's how we do it:
+We've just beta-expanded the familiar `f (u e) e` into `(fun v -> f v
+e) (u e)`, in order to factor out the parts where any Reader monad is
+being supplied as an argument to another function, as illustrated in
+the `bind` function in the following example. Then if we want instead
+to add a Reader layer to some arbitrary other monad M, with its own
+M.unit and M.bind, here's how we do it:
(* monadic operations for the ReaderT monadic transformer *)
let bind (u : ('a, M) readerT) (f : 'a -> ('b, M) readerT) : ('b, M) readerT =
fun e -> M.bind (u e) (fun v -> f v e);;
-Notice the key differences: where before we just returned `a`, now we instead return `M.unit a`. Where before we just supplied value `u e` of type `'a reader` as an argument to a function, now we instead `M.bind` the `'a reader` to that function. Notice also the differences in the types.
+Notice the key differences: where before we just returned `a`, now we
+instead return `M.unit a`. Where before we just supplied value `u e`
+of type `'a reader` as an argument to a function, now we instead
+`M.bind` the `'a reader` to that function. Notice also the differences
+in the types.
What is the relation between Reader and ReaderT? Well, suppose you started with the Identity monad: