X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?a=blobdiff_plain;ds=inline;f=towards_monads.mdwn;h=3b217cbdf507b6a330a68c2842f21e8316328a46;hb=1338528f93c8c9761397b26743800e42a4a2b079;hp=3671d2730cf38bb5639032ce7a25920787ff53d8;hpb=34c70399625b1a258682e542622d3c26d3b3795a;p=lambda.git diff --git a/towards_monads.mdwn b/towards_monads.mdwn index 3671d273..3b217cbd 100644 --- a/towards_monads.mdwn +++ b/towards_monads.mdwn @@ -29,40 +29,40 @@ let div' (x:int) (y:int) = (* val div' : int -> int -> int option = fun -# div' 12 3;; -- : int option = Some 4 +# div' 12 2;; +- : int option = Some 6 # div' 12 0;; - : int option = None -# div' (div' 12 3) 2;; +# div' (div' 12 2) 3;; Characters 4-14: - div' (div' 12 3) 2;; - ^^^^^^^^^^ + div' (div' 12 2) 3;; + ^^^^^^^^^^ Error: This expression has type int option but an expression was expected of type int *) -This starts off well: dividing 12 by 3, no problem; dividing 12 by 0, +This starts off well: dividing 12 by 2, no problem; dividing 12 by 0, just the behavior we were hoping for. But we want to be able to use the output of the safe-division function as input for further division operations. So we have to jack up the types of the inputs:
-let div' (x:int option) (y:int option) = - match y with +let div' (u:int option) (v:int option) = + match v with None -> None | Some 0 -> None - | Some n -> (match x with + | Some y -> (match u with None -> None - | Some m -> Some (m / n));; + | Some x -> Some (x / y));; (* val div' : int option -> int option -> int option =@@ -74,25 +74,25 @@ I prefer to line up the `match` alternatives by using OCaml's built-in tuple type:-# div' (Some 12) (Some 4);; -- : int option = Some 3 +# div' (Some 12) (Some 2);; +- : int option = Some 6 # div' (Some 12) (Some 0);; - : int option = None -# div' (div' (Some 12) (Some 0)) (Some 4);; +# div' (div' (Some 12) (Some 0)) (Some 3);; - : int option = None *)
-let div' (x:int option) (y:int option) = - match (x, y) with +let div' (u:int option) (v:int option) = + match (u, v) with (None, _) -> None | (_, None) -> None | (_, Some 0) -> None - | (Some m, Some n) -> Some (m / n);; + | (Some x, Some y) -> Some (x / y);;So far so good. But what if we want to combine division with other arithmetic operations? We need to make those other operations -aware of the possibility that one of their arguments will trigger a +aware of the possibility that one of their arguments has triggered a presupposition failure:
-let add' (x:int option) (y:int option) = - match (x, y) with +let add' (u:int option) (v:int option) = + match (u, v) with (None, _) -> None | (_, None) -> None - | (Some m, Some n) -> Some (m + n);; + | (Some x, Some y) -> Some (x + y);; (* val add' : int option -> int option -> int option =@@ -112,23 +112,23 @@ Haskell, etc., is to define a `bind` operator (the name `bind` is not well chosen to resonate with linguists, but what can you do). To continue our mnemonic association, we'll put a `'` after the name "bind" as well. -let bind' (x: int option) (f: int -> (int option)) = - match x with +let bind' (u: int option) (f: int -> (int option)) = + match u with None -> None - | Some n -> f n;; + | Some x -> f x;; -let add' (x: int option) (y: int option) = - bind' x (fun x -> bind' y (fun y -> Some (x + y)));; +let add' (u: int option) (v: int option) = + bind' u (fun x -> bind' v (fun y -> Some (x + y)));; -let div' (x: int option) (y: int option) = - bind' x (fun x -> bind' y (fun y -> if (0 = y) then None else Some (x / y)));; +let div' (u: int option) (v: int option) = + bind' u (fun x -> bind' v (fun y -> if (0 = y) then None else Some (x / y)));; (* -# div' (div' (Some 12) (Some 2)) (Some 4);; -- : int option = Some 1 -# div' (div' (Some 12) (Some 0)) (Some 4);; +# div' (div' (Some 12) (Some 2)) (Some 3);; +- : int option = Some 2 +# div' (div' (Some 12) (Some 0)) (Some 3);; - : int option = None -# add' (div' (Some 12) (Some 0)) (Some 4);; +# add' (div' (Some 12) (Some 0)) (Some 3);; - : int option = None *)