-Calling the function now involves some extra verbosity, but it gives us what we need: now we can try to divide by anything we
-want, without fear that we're going to trigger system errors.
-
-I prefer to line up the `match` alternatives by using OCaml's
-built-in tuple type:
-
-<pre>
-let safe_div2 (u:int option) (v:int option) =
- match (u, v) with
- | (None, _) -> None
- | (_, None) -> None
- | (_, Some 0) -> None
- | (Some x, Some y) -> Some (x / y);;
-</pre>
-
-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 has already triggered a
-presupposition failure:
-
-<pre>
-let safe_add (u:int option) (v:int option) =
- match (u, v) with
- | (None, _) -> None
- | (_, None) -> None
- | (Some x, Some y) -> Some (x + y);;
-
-(*
-val safe_add : int option -> int option -> int option = <fun>
-# safe_add (Some 12) (Some 4);;
-- : int option = Some 16
-# safe_add (safe_div (Some 12) (Some 0)) (Some 4);;
-- : int option = None
-*)
-</pre>
-
-This works, but is somewhat disappointing: the `safe_add` operation
-doesn't trigger any presupposition of its own, so it is a shame that
-it needs to be adjusted because someone else might make trouble.
-
-But we can automate the adjustment, using the monadic machinery we introduced above.
-As we said, there needs to be different `>>=`, `map2` and so on operations for each
-monad or box type we're working with.
-Haskell finesses this by "overloading" the single symbol `>>=`; you can just input that
-symbol and it will calculate from the context of the surrounding type constraints what
-monad you must have meant. In OCaml, the monadic operators are not pre-defined, but we will
-give you a library that has definitions for all the standard monads, as in Haskell.
-For now, though, we will define our `>>=` and `map2` operations by hand:
-
-<pre>
-let (>>=) (u : 'a option) (j : 'a -> 'b option) : 'b option =
- match u with
- | None -> None
- | Some x -> j x;;
-
-let map2 (f : 'a -> 'b -> 'c) (u : 'a option) (v : 'b option) : 'c option =
- u >>= (fun x -> v >>= (fun y -> Some (f x y)));;
-
-let safe_add3 = map2 (+);; (* that was easy *)
-
-let safe_div3 (u: int option) (v: int option) =
- u >>= (fun x -> v >>= (fun y -> if 0 = y then None else Some (x / y)));;
-</pre>
-
-Haskell has an even more user-friendly notation for defining `safe_div3`, namely:
-
- safe_div3 :: Maybe Int -> Maybe Int -> Maybe Int
- safe_div3 u v = do {x <- u;
- y <- v;
- if 0 == y then Nothing else Just (x `div` y)}
-
-Let's see our new functions in action:
-
-<pre>
-(*
-# safe_div3 (safe_div3 (Some 12) (Some 2)) (Some 3);;
-- : int option = Some 2
-# safe_div3 (safe_div3 (Some 12) (Some 0)) (Some 3);;
-- : int option = None
-# safe_add3 (safe_div3 (Some 12) (Some 0)) (Some 3);;
-- : int option = None
-*)
-</pre>