X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=week7.mdwn;h=abb6cfe82690c24556155b8dcf0b730bddcc2535;hp=d3e4b47d83a55932689897ddcae492bbb277f074;hb=7d27bb2510dd466a8c8135d83b3dc0150ce93bef;hpb=1690318d1a76220c9524ae083bf101e349bffac0 diff --git a/week7.mdwn b/week7.mdwn index d3e4b47d..abb6cfe8 100644 --- a/week7.mdwn +++ b/week7.mdwn @@ -58,12 +58,11 @@ operations. So we have to jack up the types of the inputs:
``` let div' (u:int option) (v:int option) =
-  match v with
+  match u with
None -> None
-    | Some 0 -> None
-	| Some y -> (match u with
-					  None -> None
-                    | Some x -> Some (x / y));;
+	| Some x -> (match v with
+				  Some 0 -> None
+				| Some y -> Some (x / y));;

(*
val div' : int option -> int option -> int option =
@@ -152,35 +151,6 @@ None objects or real numbers---those details are hidden inside of the
The definition of `div'` shows exactly what extra needs to be said in
order to trigger the no-division-by-zero presupposition.

-For linguists: this is a complete theory of a particularly simply form
-of presupposition projection (every predicate is a hole).
-
-
-
-
------------------
-
-Start by (re)reading the discussion of monads in the lecture notes for
-In those notes, we saw a way to separate thinking about error
-conditions (such as trying to divide by zero) from thinking about
-normal arithmetic computations.  We did this by making use of the
-`option` type: in each place where we had something of type `int`, we
-put instead something of type `int option`, which is a sum type
-consisting either of one choice with an `int` payload, or else a `None`
-choice which we interpret as  signaling that something has gone wrong.
-
-The goal was to make normal computing as convenient as possible: when
-any new errors, so we do want to think about the difference between
-`int`s and `int option`s.  We tried to accomplish this by defining a
-`bind` operator, which enabled us to peel away the `option` husk to get
-at the delicious integer inside.  There was also a homework problem
-which made this even more convenient by mapping any binary operation
-on plain integers into a lifted operation that understands how to deal
-with `int option`s in a sensible way.
-
[Linguitics note: Dividing by zero is supposed to feel like a kind of
presupposition failure.  If we wanted to adapt this approach to
building a simple account of presupposition projection, we would have
@@ -196,6 +166,29 @@ material that otherwise would trigger a presupposition violation; but,
not surprisingly, these refinements will require some more
sophisticated techniques than the super-simple option monad.]

+
+-----------------
+
+We've just seen a way to separate thinking about error conditions
+(such as trying to divide by zero) from thinking about normal
+arithmetic computations.  We did this by making use of the `option`
+type: in each place where we had something of type `int`, we put
+instead something of type `int option`, which is a sum type consisting
+either of one choice with an `int` payload, or else a `None` choice
+which we interpret as signaling that something has gone wrong.
+
+The goal was to make normal computing as convenient as possible: when
+any new errors, so we would rather not think about the difference
+between `int`s and `int option`s.  We tried to accomplish this by
+defining a `bind` operator, which enabled us to peel away the `option`
+husk to get at the delicious integer inside.  There was also a
+homework problem which made this even more convenient by defining a
+`lift` operator that mapped any binary operation on plain integers
+into a lifted operation that understands how to deal with `int
+option`s in a sensible way.
+
So what exactly is a monad?  We can consider a monad to be a system
that provides at least the following three elements:

@@ -216,7 +209,12 @@ that provides at least the following three elements:
discussing earlier (whose value is written `()`). It's also only
very loosely connected to the "return" keyword in many other
programming languages like C. But these are the names that the literature
-	uses.
+	uses.  [The rationale for "unit" comes from the monad laws
+	(see below), where the unit function serves as an identity,
+	just like the unit number (i.e., 1) serves as the identity
+	object for multiplication.  The rationale for "return" comes
+	from a misguided desire to resonate with C programmers and
+	other imperative types.]

The unit/return operation is a way of lifting an ordinary object into
the monadic box you've defined, in the simplest way possible. You can think
@@ -238,7 +236,7 @@ that provides at least the following three elements:
most straightforward way to lift an ordinary value into a monadic value
of the monadic type in question.

-*	Thirdly, an operation that's often called `bind`. This is another
+*	Thirdly, an operation that's often called `bind`. As we said before, this is another
unfortunate name: this operation is only very loosely connected to
what linguists usually mean by "binding." In our option/maybe monad, the
bind operation is:
@@ -276,6 +274,8 @@ that provides at least the following three elements:
be defined so as to make sure that the result of `f x` was also
a singing box. If `f` also wanted to insert a song, you'd have to decide
whether both songs would be carried through, or only one of them.
+        (Are you beginning to realize how wierd and wonderful monads
+	can be?)

There is no single `bind` function that dictates how this must go.
For each new monadic type, this has to be worked out in an
@@ -285,17 +285,11 @@ So the "option/maybe monad" consists of the polymorphic `option` type, the
`unit`/return function, and the `bind` function.

-A note on notation: Haskell uses the infix operator `>>=` to stand
-for `bind`. Chris really hates that symbol.  Following Wadler, he prefers to
-use an infix five-pointed star ⋆, or on a keyboard, `*`. Jim on the other hand
-thinks `>>=` is what the literature uses and students won't be able to
-avoid it. Moreover, although ⋆ is OK (though not a convention that's been picked up), overloading the multiplication symbol invites its own confusion
-and Jim feels very uneasy about that. If not `>>=` then we should use
-some other unfamiliar infix symbol (but `>>=` already is such...)
+A note on notation: Haskell uses the infix operator `>>=` to stand for
+`bind`: wherever you see `u >>= f`, that means `bind u f`.

-In any case, the course leaders will work this out somehow. In the meantime,
-as you read around, wherever you see `u >>= f`, that means `bind u f`. Also,
-if you ever see this notation:
+Also, if you ever see this notation:

do
x <- u
@@ -309,9 +303,14 @@ Similarly:
y <- v
f x y

-is shorthand for `u >>= (\x -> v >>= (\y -> f x y))`, that is, `bind u (fun x
--> bind v (fun y -> f x y))`. Those who did last week's homework may recognize
-this last expression.
+is shorthand for `u >>= (\x -> v >>= (\y -> f x y))`, that is, `bind u
+(fun x -> bind v (fun y -> f x y))`. Those who did last week's
+homework may recognize this last expression.  You can think of the
+notation like this: take the singing box `u` and evaluate it (which
+includes listening to the song).  Take the int contained in the
+singing box (the end result of evaluting `u`) and bind the variable
+`x` to that int.  So `x <- u` means "Sing me up an int, which I'll call
+`x`".

(Note that the above "do" notation comes from Haskell. We're mentioning it here
@@ -366,64 +365,69 @@ Just like good robots, monads must obey three laws designed to prevent
them from hurting the people that use them or themselves.

*	**Left identity: unit is a left identity for the bind operation.**
-	That is, for all `f:'a -> 'a m`, where `'a m` is a monadic
-	type, we have `(unit x) * f == f x`.  For instance, `unit` is itself
+	That is, for all `f:'a -> 'b m`, where `'b m` is a monadic
+	type, we have `(unit x) >>= f == f x`.  For instance, `unit` is itself
a function of type `'a -> 'a m`, so we can use it for `f`:

# let unit x = Some x;;
val unit : 'a -> 'a option =
-		# let ( * ) u f = match u with None -> None | Some x -> f x;;
-		val ( * ) : 'a option -> ('a -> 'b option) -> 'b option =
+		# let ( >>= ) u f = match u with None -> None | Some x -> f x;;
+		val ( >>= ) : 'a option -> ('a -> 'b option) -> 'b option =

The parentheses is the magic for telling OCaml that the
function to be defined (in this case, the name of the function
-	is `*`, pronounced "bind") is an infix operator, so we write
-	`u * f` or `( * ) u f` instead of `* u f`. Now:
+	is `>>=`, pronounced "bind") is an infix operator, so we write
+	`u >>= f` or equivalently `( >>= ) u f` instead of `>>= u
+	f`.

# unit 2;;
- : int option = Some 2
-		# unit 2 * unit;;
+		# unit 2 >>= unit;;
- : int option = Some 2

+	Now, for a less trivial instance of a function from `int`s to `int option`s:
+
# let divide x y = if 0 = y then None else Some (x/y);;
val divide : int -> int -> int option =
# divide 6 2;;
- : int option = Some 3
-		# unit 2 * divide 6;;
+		# unit 2 >>= divide 6;;
- : int option = Some 3

# divide 6 0;;
- : int option = None
-		# unit 0 * divide 6;;
+		# unit 0 >>= divide 6;;
- : int option = None

*	**Associativity: bind obeys a kind of associativity**. Like this:

-		(u * f) * g == u * (fun x -> f x * g)
+		(u >>= f) >>= g == u >>= (fun x -> f x >>= g)

-	If you don't understand why the lambda form is necessary (the "fun
-	x" part), you need to look again at the type of `bind`.
+	If you don't understand why the lambda form is necessary (the
+	"fun x -> ..." part), you need to look again at the type of `bind`.

-	Some examples of associativity in the option monad:
+	Some examples of associativity in the option monad (bear in
+	mind that in the Ocaml implementation of integer division, 2/3
+	evaluates to zero, throwing away the remainder):

-		# Some 3 * unit * unit;;
+		# Some 3 >>= unit >>= unit;;
- : int option = Some 3
-		# Some 3 * (fun x -> unit x * unit);;
+		# Some 3 >>= (fun x -> unit x >>= unit);;
- : int option = Some 3

-		# Some 3 * divide 6 * divide 2;;
+		# Some 3 >>= divide 6 >>= divide 2;;
- : int option = Some 1
-		# Some 3 * (fun x -> divide 6 x * divide 2);;
+		# Some 3 >>= (fun x -> divide 6 x >>= divide 2);;
- : int option = Some 1

-		# Some 3 * divide 2 * divide 6;;
+		# Some 3 >>= divide 2 >>= divide 6;;
- : int option = None
-		# Some 3 * (fun x -> divide 2 x * divide 6);;
+		# Some 3 >>= (fun x -> divide 2 x >>= divide 6);;
- : int option = None

Of course, associativity must hold for *arbitrary* functions of
-type `'a -> 'a m`, where `m` is the monad type.  It's easy to
+type `'a -> 'b m`, where `m` is the monad type.  It's easy to
convince yourself that the `bind` operation for the option monad
obeys associativity by dividing the inputs into cases: if `u`
matches `None`, both computations will result in `None`; if
@@ -433,11 +437,11 @@ computations will again result in `None`; and if the value of
to `g y`.

*	**Right identity: unit is a right identity for bind.**  That is,
-	`u * unit == u` for all monad objects `u`.  For instance,
+	`u >>= unit == u` for all monad objects `u`.  For instance,

-		# Some 3 * unit;;
+		# Some 3 >>= unit;;
- : int option = Some 3
-		# None * unit;;
+		# None >>= unit;;
- : 'a option = None

If you studied algebra, you'll remember that a *monoid* is an
associative operation with a left and right identity.  For instance,
the natural numbers along with multiplication form a monoid with 1
-serving as the left and right identity.  That is, temporarily using
-`*` to mean arithmetic multiplication, `1 * u == u == u * 1` for all
+serving as the left and right identity.  That is, `1 * u == u == u * 1` for all
`u`, and `(u * v) * w == u * (v * w)` for all `u`, `v`, and `w`.  As
presented here, a monad is not exactly a monoid, because (unlike the
arguments of a monoid operation) the two arguments of the bind are of
different types.  But it's possible to make the connection between
monads and monoids much closer. This is discussed in [Monads in Category

Here are some papers that introduced monads into functional programming:

-*	[Eugenio Moggi, Notions of Computation and Monads](http://www.disi.unige.it/person/MoggiE/ftp/ic91.pdf): Information and Computation 93 (1) 1991.
+*	[Eugenio Moggi, Notions of Computation and Monads](http://www.disi.unige.it/person/MoggiE/ftp/ic91.pdf): Information and Computation 93 (1) 1991. Would be very difficult reading for members of this seminar. However, the following two papers should be accessible.
+
+invited talk, *19'th Symposium on Principles of Programming Languages*, ACM Press, Albuquerque, January 1992.
+

in M. Broy, editor, *Marktoberdorf Summer School on Program Design
Calculi*, Springer Verlag, NATO ASI Series F: Computer and systems
sciences, Volume 118, August 1992. Also in J. Jeuring and E. Meijer,
editors, *Advanced Functional Programming*, Springer Verlag,
-LNCS 925, 1995. Some errata fixed August 2001.  This paper has a great first
-line: **Shall I be pure, or impure?**
+LNCS 925, 1995. Some errata fixed August 2001.

-invited talk, *19'th Symposium on Principles of Programming Languages*, ACM Press, Albuquerque, January 1992.
-
-
-*	[Daniel Friedman. A Schemer's View of Monads](/schemersviewofmonads.ps): from  but the link above is to a local copy.

-There's a long list of monad tutorials on the [[Offsite Reading]] page. Skimming the titles makes me laugh.
+There's a long list of monad tutorials on the [[Offsite Reading]] page. (Skimming the titles is somewhat amusing.) If you are confused by monads, make use of these resources. Read around until you find a tutorial pitched at a level that's helpful for you.

In the presentation we gave above---which follows the functional programming conventions---we took `unit`/return and `bind` as the primitive operations. From these a number of other general monad operations can be derived. It's also possible to take some of the others as primitive. The [Monads in Category

Here are some of the other general monad operations. You don't have to master these; they're collected here for your reference.

@@ -499,7 +500,7 @@ that is:

You could also do `bind u (fun x -> v)`; we use the `_` for the function argument to be explicit that that argument is never going to be used.

-The `lift` operation we asked you to define for last week's homework is a common operation. The second argument to `bind` converts `'a` values into `'b m` values---that is, into instances of the monadic type. What if we instead had a function that merely converts `'a` values into `'b` values, and we want to use it with our monadic type. Then we "lift" that function into an operation on the monad. For example:
+The `lift` operation we asked you to define for last week's homework is a common operation. The second argument to `bind` converts `'a` values into `'b m` values---that is, into instances of the monadic type. What if we instead had a function that merely converts `'a` values into `'b` values, and we want to use it with our monadic type? Then we "lift" that function into an operation on the monad. For example:

# let even x = (x mod 2 = 0);;
val g : int -> bool =
@@ -574,15 +575,15 @@ Monad outlook
-------------

We're going to be using monads for a number of different things in the
-weeks to come.  The first main application will be the State monad,
+weeks to come.  One major application will be the State monad,
which will enable us to model mutation: variables whose values appear
to change as the computation progresses.  Later, we will study the