index 78a4150..857a636 100644 (file)
@@ -6,6 +6,10 @@ Towards Monads: Safe division

[This section used to be near the end of the lecture notes for week 6]

+We begin by reasoning about what should happen when someone tries to
+divide by zero.  This will lead us to a general programming technique
+called a *monad*, which we'll see in many guises in the weeks to come.
+
Integer division presupposes that its second argument
(the divisor) is not zero, upon pain of presupposition failure.
Here's what my OCaml interpreter says:
@@ -148,35 +152,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
@@ -192,6 +167,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:

@@ -212,7 +210,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
@@ -272,6 +275,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
@@ -281,17 +286,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 &#8902;, 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 &#8902; 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
@@ -305,9 +304,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
@@ -363,59 +367,63 @@ 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
+       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 = <fun>
-               # let ( * ) u f = match u with None -> None | Some x -> f x;;
-               val ( * ) : 'a option -> ('a -> 'b option) -> 'b option = <fun>
+               # let ( >>= ) u f = match u with None -> None | Some x -> f x;;
+               val ( >>= ) : 'a option -> ('a -> 'b option) -> 'b option = <fun>

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`. Now, for a less trivial instance of a function from `int`s
+       to `int option`s:

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

# let divide x y = if 0 = y then None else Some (x/y);;
val divide : int -> int -> int option = <fun>
# 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`.

-       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
@@ -429,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:
@@ -474,10 +481,10 @@ invited talk, *19'th Symposium on Principles of Programming Languages*, ACM Pres

*      [Daniel Friedman. A Schemer's View of Monads](/schemersviewofmonads.ps): from <https://www.cs.indiana.edu/cgi-pub/c311/doku.php?id=home> 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 makes us laugh.

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