X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=week7.mdwn;h=0e9f25ef8455d508c33571e9734d644e59e50d94;hp=e4e884bcbd6a38fcef93cdc50204bb1ca8aafa45;hb=b0139eb9a0b1865ca04f76157ce8dcfbd203374b;hpb=6c44248b27640d43b5a683bb580f83e5cef08a28 diff --git a/week7.mdwn b/week7.mdwn index e4e884bc..0e9f25ef 100644 --- a/week7.mdwn +++ b/week7.mdwn @@ -310,8 +310,8 @@ 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, and I'll call -it `x`". +`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 because you're likely to see it when reading about monads. It won't work in @@ -367,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 = - # 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`. 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 = # 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 @@ -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 @@ -447,14 +451,13 @@ More details about monads 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 -Theory](/advanced_notes/monads_in_category_theory). +Theory](/advanced_topics/monads_in_category_theory). See also . Here are some papers that introduced monads into functional programming: @@ -478,7 +481,7 @@ invited talk, *19'th Symposium on Principles of Programming Languages*, ACM Pres * [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 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 Theory](/advanced_notes/monads_in_category_theory) notes do so, for example. @@ -499,7 +502,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 =