6.S050
Created: 2023-05-11 Thu 11:06
let plusone x = x + 1
let square x = x * x
let plusone' x = (x + 1, "added one")
let square' x = (x * x, "squared")
plusone (square 5) => 26
plusone' (square' 5) => Type error
let (x, msg1) = square' 5 in
let (y, msg2) = plusone' x in
(y, msg1 ^ " " ^ msg2)
val bind : (int * string) ->
(int -> (int * string)) ->
(int * string)
let bind (x, s) f = let (y, s') = f x in (y, s ^ s')
bind (bind (5, "") square') plusone' => (26, "plusone' square'")
val bind : (int * string) ->
(int -> (int * string)) ->
(int * string)
let bind (x, s) f = let (y, s') = f x in (y, s ^ s')
val return : int -> (int * string)
let return x = (x, "")
bind (bind (return 5) square') plusone' => (26, "plusone' square'")
val random : state -> (int * state)
let add_rand x state =
let (state, y) = random state in
(x + y, state)
let add_rand_twice x state =
let (x', state') = add_rand x state in
add_rand x' state'
val bind : (state -> 'a * state) ->
('a -> (state -> 'b * state)) ->
(state -> 'b * state)
let bind r f state = let (x, state') = r in f x state'
val return : 'a -> (state -> 'a * state)
let return x state = (x, state)
let add_rand_twice x state =
bind (bind (return x) add_rand) add_rand
(* debug info *)
val bind : (int * string) ->
(int -> (int * string)) ->
(int * string)
val return : int -> (int * string)
(* random numbers *)
val bind : (state -> 'a * state) ->
('a -> (state -> 'b * state)) ->
(state -> 'b * state)
val return : 'a -> (state -> 'a * state)
(* general purpose *)
val bind : ? -> ? -> ?
val return : ? -> ?
(* debug info *)
val bind : ('a * string) ->
('a -> ('b * string)) ->
('b * string)
val return : 'a -> ('a * string)
(* random numbers *)
val bind : (state -> 'a * state) ->
('a -> (state -> 'b * state)) ->
(state -> 'b * state)
val return : 'a -> (state -> 'a * state)
val bind : ? -> ? -> ?
val return : ? -> ?
(* debug info *)
type 'a m = 'a * string
val bind : 'a m -> ('a -> 'b m) -> 'b m
val return : 'a -> 'a m
(* random numbers *)
type 'a m = state -> 'a * state
val bind : 'a m -> ('a -> 'b m) -> 'b m
val return : 'a -> 'a m
type 'a m
val bind : 'a m -> ('a -> 'b m) -> 'b m
val return : 'a -> 'a m
'a m
is the "data we care about" + "some extra stuff"
val bind : 'a m -> ('a -> 'b m) -> 'b m
val (>>=) : 'a m -> ('a -> 'b m) -> 'b m
bind (return 5) plusone' == (return 5) >>= plusone'
value >>= consumer
So far we've seen:
Does that really justify the hype? No, not really.
More generally, we can use these operators to compose functions that produce a value & an effect:
val divide : int -> int -> int
let divide x y = x / y
divide 4 0 ==> ?
val divide : int -> int -> int
let divide x y = if y = 0 then failwith "divide by zero!" else x / y
divide
is really a partial function
divide x 0
isn't defineddivide
is defined or not(* a maybe type *)
type 'a m = Some of 'a | None
val divide : int -> int -> int m
let divide x y = if y = 0 then None else Some (x / y)
How do we compose functions that return Maybe
?
type 'a m = Some of 'a | None
val divide : int -> int -> int m
val add : int -> int -> int
val divide_and_add : int -> int -> int -> int m
let divide_and_add x y z =
match divide x y with
| None -> None
| Some q -> Some (add z q)
divide_and_add 6 2 1 ==> Some 4
divide_and_add 7 0 2 ==> None
val bind : 'a m -> ('a -> 'b m) -> 'b m
val return : 'a -> 'a m
val divide_and_add : int -> int -> int -> int m
let divide_and_add x y z =
bind (divide x y) (fun q -> return (add z q))
val bind : 'a m -> ('a -> 'b m) -> 'b m
val return : 'a -> 'a m
val divide_and_add : int -> int -> int -> int m
let divide_and_add x y z =
divide x y >>= fun q -> return (add z q)
val bind : 'a m -> ('a -> 'b m) -> 'b m
let bind x f = ??
val return : 'a -> 'a m
let return x = ??
val bind : 'a m -> ('a -> 'b m) -> 'b m
let bind x f = ??
val return : 'a -> 'a m
let return x = Some x
val bind : 'a m -> ('a -> 'b m) -> 'b m
let bind x f = match x with
| Some y -> f y
| None -> None
val return : 'a -> 'a m
let return x = Some x
val bind : 'a m -> ('a -> 'b m) -> 'b m
val return : 'a -> 'a m
val divide_and_add : int -> int -> int -> int m
let divide_and_add x y z =
divide x y >>= fun q -> return (add z q)
return
val bind : 'a m -> ('a -> 'b m) -> 'b m
val return : 'a -> 'a m
(* one more combinator! *)
val map : 'a m -> ('a -> 'b) -> 'b m
val divide_and_add : int -> int -> int -> int m
let divide_and_add x y z =
map (divide x y) (add z)
val bind : 'a m -> ('a -> 'b m) -> 'b m
val return : 'a -> 'a m
(* one more combinator! *)
val map : 'a m -> ('a -> 'b) -> 'b m
val (>>|) : 'a m -> ('a -> 'b) -> 'b m
val divide_and_add : int -> int -> int -> int m
let divide_and_add x y z =
divide x y >>| add z
val map : 'a m -> ('a -> 'b) -> 'b m
let map x f = ??
val map : 'a m -> ('a -> 'b) -> 'b m
let map x f = match x with
| Some y -> Some (f y)
| None -> None
val map : 'a m -> ('a -> 'b) -> 'b m
let map x f = match x with
| Some y -> return (f y)
| None -> None
val map : 'a m -> ('a -> 'b) -> 'b m
let map x f = bind x (fun y -> return (f y))
type 'a m = Ok of 'a | Error of string
let divide x y =
if y = 0 then Error "divide by zero!" else Ok (x / y)
divide_and_add 6 2 1 ==> Ok 4
divide_and_add 7 0 2 ==> Error "divide by zero!"
bind
and return
type 'a m = Ok of 'a | Error of string
val return : 'a -> 'a m
let return x = ??
type 'a m = Ok of 'a | Error of string
val return : 'a -> 'a m
let return x = Ok x
type 'a m = Ok of 'a | Error of string
val return : 'a -> 'a m
let return x = Ok x
val bind : 'a m -> ('a -> 'b m) -> 'b m
let bind x f = ??
type 'a m = Ok of 'a | Error of string
val return : 'a -> 'a m
let return x = Ok x
val bind : 'a m -> ('a -> 'b m) -> 'b m
let bind x f = match x with
| Ok x -> f x
| Error e -> Error e
(* a computation that does some IO and produces an 'a *)
type 'a io
(* sequencing IO computations *)
val bind : 'a io -> ('a -> 'b io) -> 'b io
val return : 'a -> 'a io
val read_char : char io
val write_char : char -> unit io
val read_line : string io
val write_line : string -> unit io
let say_hello =
write_line "What's your name? "
>>= fun () -> read_line
>>= fun name -> write_line ("Hello " ^ name ^ "!\n")
type 'a io =
| Read : string io
| Write : string -> unit io
| Bind : 'a io * ('a -> 'b io) -> 'b io
| Return : 'a -> 'a io
let read_line = Read
let write_line s = Write s
let bind m f = Bind (m, f)
let (>>=) = bind
let return x = Return x
let say_hello =
write_line "What's your name? "
>>= fun () -> read_line
>>= fun name -> write_line ("Hello " ^ name ^ "!\n")
let say_hello' =
Bind (Write "What's your name?",
fun () -> Bind (Read,
fun name -> Bind (Write ("Hello " ^ name ^ "!"),
fun () -> Return ())))
let rec run : 'a. 'a io -> 'a =
fun (type a) (io : a io) : a ->
match io with
| Read -> "Frank"
| Write s -> print_endline s
| Bind (m, f) -> run (f (run m))
| Return x -> x
;;
run say_hello
: What's your name? : Hello Frank! :