X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=zipper-lists-continuations.mdwn;h=9ef23c250e4d3c71affbb3a0d40ce72ad156e51c;hp=edc3359d66015d9a0547d02ba7b35c644ff726cf;hb=1758d3493aeb5a8ab805b6cfea11080f72792978;hpb=789245157230b7010000b0ce3290d45bd5a9d8fa
diff --git a/zipper-lists-continuations.mdwn b/zipper-lists-continuations.mdwn
index edc3359d..9ef23c25 100644
--- a/zipper-lists-continuations.mdwn
+++ b/zipper-lists-continuations.mdwn
@@ -73,7 +73,7 @@ The **State Monad** is similar. Once we've decided to use the following type co
Then our unit is naturally:
- let s_unit (x : 'a) : ('a state) = fun (s : store) -> (x, s)
+ let s_unit (a : 'a) : ('a state) = fun (s : store) -> (a, s)
And we can reason our way to the bind function in a way similar to the reasoning given above. First, we need to apply `f` to the contents of the `u` box:
@@ -100,7 +100,7 @@ Our other familiar monad is the **List Monad**, which we were told
looks like this:
type 'a list = ['a];;
- l_unit (x : 'a) = [x];;
+ l_unit (a : 'a) = [a];;
l_bind u f = List.concat (List.map f u);;
Recall that `List.map` take a function and a list and returns the
@@ -167,7 +167,7 @@ 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 (a : 'a) : ('a, 'b) list = fun a -> fun f z -> f a z
No problem. Arriving at bind is a little more complicated, but
exactly the same principles apply, you just have to be careful and
@@ -219,11 +219,48 @@ Here's a way to persuade yourself that it will have the right behavior. First, i
Now let's think about what this does. It's a wrapper around `u`. In order to behave as the list which is the result of mapping `f` over each element of `u`, and then joining (`concat`ing) the results, this wrapper would have to accept arguments `k` and `z` and fold them in just the same way that the list which is the result of mapping `f` and then joining the results would fold them. Will it?
-... MORE...
+Suppose we have a list' whose contents are `[1; 2; 4; 8]`---that is, our list' will be `fun f z -> f 1 (f 2 (f 4 (f 8 z)))`. We call that list' `u`. Suppose we also have a function `f` that for each `int` we give it, gives back a list of the divisors of that `int` that are greater than 1. Intuitively, then, binding `u` to `f` should give us:
+ concat (map f u) =
+ concat [[]; [2]; [2; 4]; [2; 4; 8]] =
+ [2; 2; 4; 2; 4; 8]
-Our theory is that this monad should be capable of exactly
-replicating the behavior of the standard List monad. Let's test:
+Or rather, it should give us a list' version of that, which takes a function `k` and value `z` as arguments, and returns the right fold of `k` and `z` over those elements. What does our formula
+
+ fun k z -> u (fun a b -> f a k b) z
+
+do? Well, for each element `a` in `u`, it applies `f` to that `a`, getting one of the lists:
+
+ []
+ [2]
+ [2; 4]
+ [2; 4; 8]
+
+(or rather, their list' versions). Then it takes the accumulated result `b` of previous steps in the fold, and it folds `k` and `b` over the list generated by `f a`. The result of doing so is passed on to the next step as the accumulated result so far.
+
+So if, for example, we let `k` be `+` and `z` be `0`, then the computation would proceed:
+
+ 0 ==>
+ right-fold + and 0 over [2; 4; 8] = 2+4+8+0 ==>
+ right-fold + and 2+4+8+0 over [2; 4] = 2+4+2+4+8+0 ==>
+ right-fold + and 2+4+2+4+8+0 over [2] = 2+2+4+2+4+8+0 ==>
+ right-fold + and 2+2+4+2+4+8+0 over [] = 2+2+4+2+4+8+0
+
+which indeed is the result of right-folding + and 0 over `[2; 2; 4; 2; 4; 8]`. If you trace through how this works, you should be able to persuade yourself that our formula:
+
+ fun k z -> u (fun a b -> f a k b) z
+
+will deliver just the same folds, for arbitrary choices of `k` and `z` (with the right types), and arbitrary list's `u` and appropriately-typed `f`s, as
+
+ fun k z -> List.fold_right k (concat (map f u)) z
+
+would.
+
+For future reference, we might make two eta-reductions to our formula, so that we have instead:
+
+ let l'_bind = fun k -> u (fun a -> f a k);;
+
+Let's make some more tests:
l_bind [1;2] (fun i -> [i, i+1]) ~~> [1; 2; 2; 3]
@@ -262,7 +299,7 @@ generalized quantifier `fun pred -> pred j` of type `(e -> t) -> t`.
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 (a : e) = fun (p : e -> t) -> p a
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
@@ -271,16 +308,16 @@ belabor the construction of the bind function, the derivation is
similar to the List monad just given:
type 'a continuation = ('a -> 'b) -> 'b
- c_unit (x : 'a) = fun (p : 'a -> 'b) -> p x
+ c_unit (a : 'a) = fun (p : 'a -> 'b) -> p a
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)
+ fun (k : 'a -> 'b) -> u (fun (a : 'a) -> f a k)
How similar is it to the List monad? Let's examine the type
constructor and the terms from the list monad derived above:
type ('a, 'b) list' = ('a -> 'b -> 'b) -> 'b -> 'b
- l'_unit x = fun f -> f x
- l'_bind u f = fun k -> u (fun x -> f x k)
+ l'_unit a = fun f -> f a
+ l'_bind u f = fun k -> u (fun a -> f a k)
(We performed a sneaky but valid eta reduction in the unit term.)