For instance, take the **Reader Monad**. Once we decide that the type
constructor is
- type 'a reader = fun e:env -> 'a
+ type 'a reader = env -> 'a
then we can deduce the unit and the bind:
- r_unit x:'a -> 'a reader = fun (e:env) -> x
+ let r_unit (x : 'a) : 'a reader = fun (e : env) -> x
-Since the type of an `'a reader` is `fun e:env -> 'a` (by definition),
-the type of the `r_unit` function is `'a -> e:env -> 'a`, which is a
+Since the type of an `'a reader` is `env -> 'a` (by definition),
+the type of the `r_unit` function is `'a -> env -> 'a`, which is a
specific case of the type of the *K* combinator. So it makes sense
that *K* is the unit for the reader monad.
Since the type of the `bind` operator is required to be
- r_bind:('a reader) -> ('a -> 'b reader) -> ('b reader)
+ r_bind : ('a reader) -> ('a -> 'b reader) -> ('b reader)
We can deduce the correct `bind` function as follows:
- r_bind (u:'a reader) (f:'a -> 'b reader):('b reader) =
+ let r_bind (u : 'a reader) (f : 'a -> 'b reader) : ('b reader) =
We have to open up the `u` box and get out the `'a` object in order to
feed it to `f`. Since `u` is a function from environments to
'b`. Once again, the easiest way to turn a `'b reader` into a `'b` is to apply it to
an environment. So we end up as follows:
- r_bind (u:'a reader) (f:'a -> 'b reader):('b reader) = f (u e) e
+ r_bind (u : 'a reader) (f : 'a -> 'b reader) : ('b reader) = f (u e) e
And we're done.
-[This bind is a simplified version of the careful `let a = u e in ...`
-constructions we provided in earlier lectures. We use the simplified
-versions here in order to emphasize similarities of structure across
-monads; the official bind is still the one with the plethora of `let`'s.]
+[This bind is a condensed version of the careful `let a = u e in ...`
+constructions we provided in earlier lectures. We use the condensed
+version here in order to emphasize similarities of structure across
+monads.]
The **State Monad** is similar. We somehow intuit that we want to use
the following type constructor:
- type 'a state = 'store -> ('a, 'store)
+ type 'a state = store -> ('a, store)
So our unit is naturally
- let s_unit (x:'a):('a state) = fun (s:'store) -> (x, s)
+ let s_unit (x : 'a) : ('a state) = fun (s : store) -> (x, s)
And we deduce the bind in a way similar to the reasoning given above.
First, we need to apply `f` to the contents of the `u` box:
- let s_bind (u:'a state) (f:'a -> ('b state)):('b state) =
+ let s_bind (u : 'a state) (f : 'a -> 'b state) : 'b state =
But unlocking the `u` box is a little more complicated. As before, we
need to posit a state `s` that we can apply `u` to. Once we do so,
Abstracting over the `s` and adjusting the types gives the result:
- let s_bind (u:'a state) (f:'a -> ('b state)):('b state) =
- fun (s:state) -> let (a, s') = u s in f a s'
+ let s_bind (u : 'a state) (f : 'a -> 'b state) : 'b state =
+ fun (s : store) -> let (a, s') = u s in f a s'
The **Option Monad** doesn't follow the same pattern so closely, so we
won't pause to explore it here, though conceptually its unit and bind
looks like this:
type 'a list = ['a];;
- l_unit (x:'a) = [x];;
+ l_unit (x : 'a) = [x];;
l_bind u f = List.concat (List.map f u);;
Recall that `List.map` take a function and a list and returns the
list with two elements: fun f z -> f 2 (f 1 z)
list with three elements: fun f z -> f 3 (f 2 (f 1 z))
-and so on. To save time, we'll let the Ocaml interpreter infer the
+and so on. To save time, we'll let the OCaml interpreter infer the
principle types of these functions (rather than deducing what the
types should be):
So an `('a, 'b) list'` is a list containing elements of type `'a`,
where `'b` is the type of some part of the plumbing. This is more
-general than an ordinary Ocaml list, but we'll see how to map them
-into Ocaml lists soon. We don't need to fully grasp the role of the `'b`'s
+general than an ordinary OCaml list, but we'll see how to map them
+into OCaml lists soon. We don't need to fully grasp the role of the `'b`'s
in order to proceed to build a monad:
- l'_unit (x:'a):(('a, 'b) list) = fun x -> fun f z -> f x z
+ l'_unit (x : 'a) : ('a, 'b) list = fun x -> fun f z -> f x z
No problem. Arriving at bind is a little more complicated, but
exactly the same principles apply, you just have to be careful and
systematic about it.
- l'_bind (u:('a,'b) list') (f:'a -> ('c, 'd) list'): ('c, 'd) list' = ...
+ l'_bind (u : ('a,'b) list') (f : 'a -> ('c, 'd) list') : ('c, 'd) list' = ...
Unfortunately, we'll need to spell out the types:
- l'_bind (u: ('a -> 'b -> 'b) -> 'b -> 'b)
- (f: 'a -> ('c -> 'd -> 'd) -> 'd -> 'd)
+ l'_bind (u : ('a -> 'b -> 'b) -> 'b -> 'b)
+ (f : 'a -> ('c -> 'd -> 'd) -> 'd -> 'd)
: ('c -> 'd -> 'd) -> 'd -> 'd = ...
It's a rookie mistake to quail before complicated types. You should
argument a function expecting an `'a`. Once that argument is applied
to an object of type `'a`, we'll have what we need. Thus:
- .... u (fun (x:'a) -> ... (f a) ... ) ...
+ .... u (fun (a : 'a) -> ... (f a) ... ) ...
In order for `u` to have the kind of argument it needs, we have to
adjust `(f a)` (which has type `('c -> 'd -> 'd) -> 'd -> 'd`) in
alias `'d` to `'b`, and provide `(f a)` with an argument of type `'c
-> 'b -> 'b`. Thus:
- l'_bind (u: ('a -> 'b -> 'b) -> 'b -> 'b)
- (f: 'a -> ('c -> 'b -> 'b) -> 'b -> 'b)
+ l'_bind (u : ('a -> 'b -> 'b) -> 'b -> 'b)
+ (f : 'a -> ('c -> 'b -> 'b) -> 'b -> 'b)
: ('c -> 'b -> 'b) -> 'b -> 'b =
- .... u (fun (x:'a) -> f a k) ...
+ .... u (fun (a : 'a) -> f a k) ...
-[Excercise: can you arrive at a fully general bind for this type
+[Exercise: can you arrive at a fully general bind for this type
constructor, one that does not collapse `'d`'s with `'b`'s?]
As usual, we have to abstract over `k`, but this time, no further
adjustments are needed:
- l'_bind (u: ('a -> 'b -> 'b) -> 'b -> 'b)
- (f: 'a -> ('c -> 'b -> 'b) -> 'b -> 'b)
+ l'_bind (u : ('a -> 'b -> 'b) -> 'b -> 'b)
+ (f : 'a -> ('c -> 'b -> 'b) -> 'b -> 'b)
: ('c -> 'b -> 'b) -> 'b -> 'b =
- fun (k:'c -> 'b -> 'b) -> u (fun (x:'a) -> f a k)
+ fun (k : 'c -> 'b -> 'b) -> u (fun (a : 'a) -> f a k)
You should carefully check to make sure that this term is consistent
with the typing.
l'_bind (fun f z -> f 1 (f 2 z))
(fun i -> fun f z -> f i (f (i+1) z)) ~~> <fun>
-Sigh. Ocaml won't show us our own list. So we have to choose an `f`
-and a `z` that will turn our hand-crafted lists into standard Ocaml
+Sigh. OCaml won't show us our own list. So we have to choose an `f`
+and a `z` that will turn our hand-crafted lists into standard OCaml
lists, so that they will print out.
-<pre>
-# let cons h t = h :: t;; (* Ocaml is stupid about :: *)
-# l'_bind (fun f z -> f 1 (f 2 z))
- (fun i -> fun f z -> f i (f (i+1) z)) cons [];;
-- : int list = [1; 2; 2; 3]
-</pre>
+ # let cons h t = h :: t;; (* OCaml is stupid about :: *)
+ # l'_bind (fun f z -> f 1 (f 2 z))
+ (fun i -> fun f z -> f i (f (i+1) z)) cons [];;
+ - : int list = [1; 2; 2; 3]
Ta da!
Let's write a general function that will map individuals into their
corresponding generalized quantifier:
- gqize (x:e) = fun (p:e->t) -> p x
+ gqize (x : e) = fun (p : e -> t) -> p x
This function wraps up an individual in a fancy box. That is to say,
we are in the presence of a monad. The type constructor, the unit and
belabor the construction of the bind function, the derivation is
similar to the List monad just given:
-<pre>
-type 'a continuation = ('a -> 'b) -> 'b
-c_unit (x:'a) = fun (p:'a -> 'b) -> p x
-c_bind (u:('a -> 'b) -> 'b) (f: 'a -> ('c -> 'd) -> 'd): ('c -> 'd) -> 'd =
- fun (k:'a -> 'b) -> u (fun (x:'a) -> f x k)
-</pre>
+ type 'a continuation = ('a -> 'b) -> 'b
+ c_unit (x : 'a) = fun (p : 'a -> 'b) -> p x
+ c_bind (u : ('a -> 'b) -> 'b) (f : 'a -> ('c -> 'd) -> 'd) : ('c -> 'd) -> 'd =
+ fun (k : 'a -> 'b) -> u (fun (x : 'a) -> f x k)
How similar is it to the List monad? Let's examine the type
constructor and the terms from the list monad derived above:
homemade List monad are the same terms! In other words, the behavior
of the List monad and the behavior of the continuations monad are
parallel in a deep sense. To emphasize the parallel, we can
-instantiate the type of the list' monad using the Ocaml list type:
+instantiate the type of the list' monad using the OCaml list type:
type 'a c_list = ('a -> 'a list) -> 'a list