- : int tree =ppp
Node (Node (Leaf 4, Leaf 9), Node (Leaf 25, Node (Leaf 49, Leaf 121)))
-Note that what `tree_map` does is take some global, contextual
+Note that what `tree_map` does is take some unchanging contextual
information---what to do to each leaf---and supplies that information
to each subpart of the computation. In other words, `tree_map` has the
behavior of a reader monad. Let's make that explicit.
With previous readers, we always knew which kind of environment to
expect: either an assignment function (the original calculator
simulation), a world (the intensionality monad), an integer (the
-Jacobson-inspired link monad), etc. In the present case, it will be
-enough to expect that our "environment" will be some function of type
-`int -> int`.
+Jacobson-inspired link monad), etc. In the present case, we expect that our "environment" will be some function of type `int -> int`. "Looking up" some `int` in the environment will return us the `int` that comes out the other side of that function.
type 'a reader = (int -> int) -> 'a;; (* mnemonic: e for environment *)
let reader_unit (a : 'a) : 'a reader = fun _ -> a;;
reader_unit (Node (x, y))));;
This function says: give me a function `f` that knows how to turn
-something of type `'a` into an `'b reader`, and I'll show you how to
-turn an `'a tree` into an `'b tree reader`. In more fanciful terms,
-the `tree_monadize` function builds plumbing that connects all of the
-leaves of a tree into one connected monadic network; it threads the
+something of type `'a` into an `'b reader`---this is a function of the same type that you could bind an `'a reader` to---and I'll show you how to
+turn an `'a tree` into an `'b tree reader`. That is, if you show me how to do this:
+
+ ------------
+ 1 ---> | 1 |
+ ------------
+
+then I'll give you back the ability to do this:
+
+ ____________
+ . | . |
+ __|___ ---> | __|___ |
+ | | | | | |
+ 1 2 | 1 2 |
+ ------------
+
+And how will that boxed tree behave? Whatever actions you perform on it will be transmitted down to corresponding operations on its leaves. For instance, our `int reader` expects an `int -> int` environment. If supplying environment `e` to our `int reader` doubles the contained `int`:
+
+ ------------
+ 1 ---> | 1 | applied to e ~~> 2
+ ------------
+
+Then we can expect that supplying it to our `int tree reader` will double all the leaves:
+
+ ____________
+ . | . | .
+ __|___ ---> | __|___ | applied to e ~~> __|___
+ | | | | | | | |
+ 1 2 | 1 2 | 2 4
+ ------------
+
+In more fanciful terms, the `tree_monadize` function builds plumbing that connects all of the leaves of a tree into one connected monadic network; it threads the
`'b reader` monad through the original tree's leaves.
# tree_monadize int_readerize t1 double;;
- : int tree =
Node (Node (Leaf 4, Leaf 9), Node (Leaf 25, Node (Leaf 49, Leaf 121)))
-Now that we have a tree transformer that accepts a reader monad as a
+Now that we have a tree transformer that accepts a *reader* monad as a
parameter, we can see what it would take to swap in a different monad.
For instance, we can use a state monad to count the number of leaves in
Then we can count the number of leaves in the tree:
- # tree_monadize (fun a s -> (a, s+1)) t1 0;;
+ # tree_monadize (fun a -> fun s -> (a, s+1)) t1 0;;
- : int tree * int =
(Node (Node (Leaf 2, Leaf 3), Node (Leaf 5, Node (Leaf 7, Leaf 11))), 5)
| |
7 11
+Why does this work? Because the operation `fun a -> fun s -> (a, s+1)` takes an `int` and wraps it in an `int state` monadic box that increments the state. When we give that same operations to our `tree_monadize` function, it then wraps an `int tree` in a box, one that does the same state-incrementing for each of its leaves.
One more revealing example before getting down to business: replacing
`state` everywhere in `tree_monadize` with `list` gives us
Unlike the previous cases, instead of turning a tree into a function
from some input to a result, this transformer replaces each `int` with
-a list of `int`'s.
+a list of `int`'s. We might also have done this with a Reader Monad, though then our environments would need to be of type `int -> int list`. Experiment with what happens if you supply the `tree_monadize` based on the List Monad an operation like `fun -> [ i; [2*i; 3*i] ]`. Use small trees for your experiment.
+
<!--
FIXME: We don't make it clear why the fun has to be int -> int list list, instead of int -> int list
continuation_unit (Node (x, y))));;
We use the continuation monad described above, and insert the
-`continuation` type in the appropriate place in the `tree_monadize` code.
-We then compute:
+`continuation` type in the appropriate place in the `tree_monadize` code. Then if we give the `tree_monadize` function an operation that converts `int`s into continuations expecting `'b` arguments, it will give us back a way to turn `int tree`s into continuations that expect `'b tree` arguments. The effect of giving the continuation such an argument will be to distribute across the `'b tree`'s leaves effects that parallel the effects that the `'b`-expecting continuations would have on their `'b`s.
+
+So for example, we compute:
- # tree_monadize (fun a k -> a :: (k a)) t1 (fun t -> []);;
+ # tree_monadize (fun a -> fun k -> a :: (k a)) t1 (fun t -> []);;
- : int list = [2; 3; 5; 7; 11]
-We have found a way of collapsing a tree into a list of its leaves.
+We have found a way of collapsing a tree into a list of its leaves. Can you trace how this is working?
The continuation monad is amazingly flexible; we can use it to
simulate some of the computations performed above. To see how, first
interesting functions for the first argument of `tree_monadize`:
(* Simulating the tree reader: distributing a operation over the leaves *)
- # tree_monadize (fun a k -> k (square a)) t1 (fun i -> i);;
+ # tree_monadize (fun a -> fun k -> k (square a)) t1 (fun i -> i);;
- : int tree =
Node (Node (Leaf 4, Leaf 9), Node (Leaf 25, Node (Leaf 49, Leaf 121)))
(* Simulating the int list tree list *)
- # tree_monadize (fun a k -> k [a; square a]) t1 (fun i -> i);;
+ # tree_monadize (fun a -> fun k -> k [a; square a]) t1 (fun i -> i);;
- : int list tree =
Node
(Node (Leaf [2; 4], Leaf [3; 9]),
Node (Leaf [5; 25], Node (Leaf [7; 49], Leaf [11; 121])))
(* Counting leaves *)
- # tree_monadize (fun a k -> 1 + k a) t1 (fun i -> 0);;
+ # tree_monadize (fun a -> fun k -> 1 + k a) t1 (fun i -> 0);;
- : int = 5
We could simulate the tree state example too, but it would require