Last time: monads (etc.) > > =
1/ 40
Last time: monads (etc.) = > > 1/ 40 This time: - - PowerPoint PPT Presentation
Last time: monads (etc.) = > > 1/ 40 This time: applicatives (etc.) 2/ 40 Example effects Effects unavailable in OCaml Effects available in OCaml non-determinism (higher-order) state amb f g h r := f; !r () first-class
1/ 40
2/ 40
Effects available in OCaml (higher-order) state r := f; !r () exceptions raise Not found I/O of various sorts input byte stdin concurrency (interleaving)
v f non-termination let rec f x = f x Effects unavailable in OCaml non-determinism amb f g h first-class continuations escape x in e polymorphic state r := ”one”; r := 2 checked exceptions int
IOError
− − − − → bool
3/ 40
An imperative program
l e t id = ! counter in l e t () = counter := id + 1 in s t r i n g o f i n t id
A monadic program
get > > = fun id → put ( id + 1) > > = fun () → r e t u r n ( s t r i n g o f i n t id )
4/ 40
monads type ’a t let .. in indexed monads type (’e, ’a) t Γ ⊢ M : A ! e parameterised monads type (’ s, ’t, ’a) t {P} C {Q}
5/ 40
composeE : (a
E
− − → b) → (b
E
− − → c) → (a
E
− − → c) pairE : (a
E
− − → b) → (c
E
− − → d) → (a × c
E
− − → b × d) uncurryE : (a
E
− − → b
E
− − → c) → (a × b
E
− − → c) liftPure : (a → b) → (a
E
− − → b)
6/ 40
v a l uncurryM : ( ’ a → ( ’ b → ’ c t ) t ) → (( ’ a ∗ ’b) → ’ c t ) l e t uncurryM f ( x , y ) = f x > > = fun g → g y
7/ 40
( let . . . and)
8/ 40
Idea: stop information flowing from one computation into another. Only allow unparameterised computations: 1
E
− − → b We can no longer write functions like this: composeE : (a
E
− − → b) → (b
E
− − → c) → (a
E
− − → c) but some useful functions are still possible: pairEstatic : (1
E
− − → a) → (1
E
− − → b) → (1
E
− − → a × b)
9/ 40
An imperative program
l e t x = fresh name () and y = fresh name () in ( x , y )
An applicative program
pure ( fun x y → ( x , y )) ⊗ fresh name ⊗ fresh name
10/ 40
module type APPLICATIVE = s i g type ’ a t v a l pure : ’ a → ’ a t v a l (⊗) : ( ’ a → ’b) t → ’ a t → ’b t end
11/ 40
module type APPLICATIVE = s i g type ’ a t v a l pure : ’ a → ’ a t v a l (⊗) : ( ’ a → ’b) t → ’ a t → ’b t end Laws: pure f ⊗ pure v ≡ pure (f v) u ≡ pure id ⊗ u u ⊗ (v ⊗ w) ≡ pure compose ⊗ u ⊗ v ⊗ w v ⊗ pure x ≡ pure (fun f → f x) ⊗ v
11/ 40
The type of > > =: ’a t → (’a → ’b t) → ’b t ’a → ’b t: a function that builds a computation (Almost) the type of ⊗: ’a t → (’a → ’b) t → ’b t (’a → ’b) t: a computation that builds a function The actual type of ⊗: (’a → ’b) t → ’a t → ’b t
12/ 40
pure f ⊗ c1 ⊗ c2 . . . ⊗ cn pure (fun x1 x2 . . . xn → e) ⊗ c1 ⊗ c2 . . . ⊗ cn l e t ! x1 = c1 and ! x2 = c2 . . . and ! xn = cn in e
13/ 40
pure f ⊗ (pure g ⊗ fresh name) ⊗ fresh name
14/ 40
pure f ⊗ (pure g ⊗ fresh name) ⊗ fresh name ≡ (composition law) (pure compose ⊗ pure f ⊗ pure g ⊗ fresh name) ⊗ fresh name
14/ 40
pure f ⊗ (pure g ⊗ fresh name) ⊗ fresh name ≡ (composition law) (pure compose ⊗ pure f ⊗ pure g ⊗ fresh name) ⊗ fresh name ≡ (homomorphism law (×2)) pure (compose f g) ⊗ fresh name ⊗ fresh name
14/ 40
module Applicative of monad (M:MONAD) : APPLICATIVE with type ’ a t = ’ a M. t = s t r u c t type ’ a t = ’ a M. t l e t pure = M. r e t u r n l e t (⊗) f p =
> = fun g → p > > = fun q → r e t u r n ( g q )) end
15/ 40
module StateA (S : s i g type t end ) : s i g type s t a t e = S . t i n c l u d e APPLICATIVE v a l get : s t a t e t v a l put : s t a t e → u n i t t v a l runState : ’ a t → i n i t : s t a t e → s t a t e ∗ ’ a end = s t r u c t type s t a t e = S . t i n c l u d e Applicative of monad ( State (S )) l e t ( get , put , runState ) = M. ( get , put , runState ) end
16/ 40
module Compose (F : APPLICATIVE) (G : APPLICATIVE) : APPLICATIVE with type ’ a t = ’ a G. t F . t = s t r u c t type ’ a t = ’ a G. t F . t l e t pure x = F . pure (G. pure x ) l e t (⊗) f x = F . ( pure G. ( ⊗) ⊗ f ⊗ x ) end
17/ 40
module D u a l a p p l i c a t i v e (A: APPLICATIVE) : APPLICATIVE with type ’ a t = ’ a A. t = s t r u c t type ’ a t = ’ a A. t l e t pure = A. pure l e t (⊗) f x =
( fun y g → g y ) ⊗ x ⊗ f ) end
18/ 40
pure f ⊗ pure x
19/ 40
pure f ⊗ pure x ≡ (definition of ⊗ and pure) F.pure (⊗G ) ⊗F F.pure (G.pure f) ⊗F F.pure (G.pure x)
19/ 40
pure f ⊗ pure x ≡ (definition of ⊗ and pure) F.pure (⊗G ) ⊗F F.pure (G.pure f) ⊗F F.pure (G.pure x) ≡ (homomorphism law for F (×2)) F.pure (G.pure f ⊗G G.pure x)
19/ 40
pure f ⊗ pure x ≡ (definition of ⊗ and pure) F.pure (⊗G ) ⊗F F.pure (G.pure f) ⊗F F.pure (G.pure x) ≡ (homomorphism law for F (×2)) F.pure (G.pure f ⊗G G.pure x) ≡ (homomorphism law for G) F.pure (G.pure (f x))
19/ 40
pure f ⊗ pure x ≡ (definition of ⊗ and pure) F.pure (⊗G ) ⊗F F.pure (G.pure f) ⊗F F.pure (G.pure x) ≡ (homomorphism law for F (×2)) F.pure (G.pure f ⊗G G.pure x) ≡ (homomorphism law for G) F.pure (G.pure (f x)) ≡ (definition of pure) pure (f x)
19/ 40
type ’ a t r e e = Empty : ’ a t r e e | Tree : ’ a t r e e ∗ ’ a ∗ ’ a t r e e → ’ a t r e e module I S t a t e = State ( s t r u c t type t = i n t end ) l e t fresh name : s t r i n g I S t a t e . t = get > > = fun i → put ( i + 1) > > = fun () → r e t u r n ( P r i n t f . s p r i n t f ”x%d” i ) l e t rec l a b e l t r e e : ’ a t r e e → s t r i n g t r e e I S t a t e . t = f u n c t i o n Empty → r e t u r n Empty | Tree ( l , v , r ) → l a b e l t r e e l > > = fun l → fresh name > > = fun name → l a b e l t r e e r > > = fun r → r e t u r n ( Tree ( l , name , r ))
20/ 40
Problem: we cannot write fresh name using the APPLICATIVE interface. l e t fresh name : s t r i n g I S t a t e . t = get > > = fun i → put ( i + 1) > > = fun () → r e t u r n ( P r i n t f . s p r i n t f ”x%d” i ) Solution: introduce it as a primitive effect: module NameA : s i g i n c l u d e APPLICATIVE v a l fresh name : s t r i n g t end = . . .
21/ 40
l e t rec l a b e l t r e e : ’ a t r e e → s t r i n g t r e e NameA. t = f u n c t i o n Empty → pure Empty | Tree ( l , v , r ) → pure ( fun l name r → Tree ( l , name , r )) ⊗ l a b e l t r e e l ⊗ fresh name ⊗ l a b e l t r e e r
22/ 40
module type MONOID = s i g type t v a l zero : t v a l (+ +) : t → t → t end module Phantom monoid (M: MONOID) : APPLICATIVE with type ’ a t = M. t = s t r u c t type ’ a t = M. t l e t pure = M. zero l e t (⊗) = M. ( + +) end
23/ 40
module type MONOID = s i g type t v a l zero : t v a l (+ +) : t → t → t end module Phantom monoid (M: MONOID) : APPLICATIVE with type ’ a t = M. t = s t r u c t type ’ a t = M. t l e t pure = M. zero l e t (⊗) = M. ( + +) end Observation: we cannot implement Phantom monoid as a monad.
23/ 40
programs ⊗ > > = implementations > > = ⊗ Some monadic programs are not applicative, e.g. fresh name. Some applicative instances are not monadic, e.g. Phantom monoid.
24/ 40
Be conservative in what you do, be liberal in what you accept from others.
25/ 40
Be conservative in what you do, be liberal in what you accept from others.
Conservative in what you do: use applicatives, not monads. (Applicatives give the implementor more freedom.)
25/ 40
Be conservative in what you do, be liberal in what you accept from others.
Conservative in what you do: use applicatives, not monads. (Applicatives give the implementor more freedom.) Liberal in what you accept: implement monads, not applicatives. (Monads give the user more power.)
25/ 40
module type PARAMETERISED APPLICATIVE = s i g type ( ’ s , ’ t , ’ a ) t v a l u n i t : ’ a → ( ’ s , ’ s , ’ a ) t v a l (⊗) : ( ’ r , ’ s , ’ a → ’b) t → ( ’ s , ’ t , ’ a ) t → ( ’ r , ’ t , ’ b) t end module type INDEXED APPLICATIVE = s i g type ( ’ e , ’ a ) t v a l pure : ’ a → ( ’ e , ’ a ) t v a l (⊗) : ( ’ e , ’ a → ’b) t → ( ’ e , ’ a ) t → ( ’ e , ’ b) t end
26/ 40
. . . x y
27/ 40
. . . x y . . . x+y Add . . . y x c . . .
(y,x)[c]
If . . . . . . c PushConst
28/ 40
module type STACK OPS = s i g type ( ’ s , ’ t , ’ a ) t v a l add : ( i n t ∗ ( i n t ∗ ’ s ) , i n t ∗ ’ s , u n i t ) t v a l i f : ( bool ∗ ( ’ a ∗ ( ’ a ∗ ’ s )) , ’ a ∗ ’ s , u n i t ) t v a l push const : ’ a → ( ’ s , ’ a ∗ ’ s , u n i t ) t end
29/ 40
module type STACKM = s i g i n c l u d e PARAMETERISED MONAD i n c l u d e STACK OPS with type ( ’ s , ’ t , ’ a ) t := ( ’ s , ’ t , ’ a ) t v a l execute : ( ’ s , ’ t , ’ a ) t → ’ s → ’ t ∗ ’ a end module StackM : STACKM = s t r u c t i n c l u d e PState l e t add = get > > = fun ( x , ( y , s )) → put ( x+y , s ) l e t i f = get ( c , ( t , ( e , s ) ) ) > > = put ( i f c then t e l s e e ) l e t push const k = get > > = fun s → put (k , s ) l e t execute = runState end
30/ 40
push const 3 > > = fun () → push const 4 > > = fun () → push const 5 > > = fun () → push const true > > = fun () → i f > > = fun () → add > > = fun () → r e t u r n ()
. . .
31/ 40
push const 3 > > = fun () → push const 4 > > = fun () → push const 5 > > = fun () → push const true > > = fun () → i f > > = fun () → add > > = fun () → r e t u r n ()
. . . . . . 3
31/ 40
push const 3 > > = fun () → push const 4 > > = fun () → push const 5 > > = fun () → push const true > > = fun () → i f > > = fun () → add > > = fun () → r e t u r n ()
. . . . . . 3 . . . 3 4
31/ 40
push const 3 > > = fun () → push const 4 > > = fun () → push const 5 > > = fun () → push const true > > = fun () → i f > > = fun () → add > > = fun () → r e t u r n ()
. . . . . . 3 . . . 3 4 . . . 3 4 5
31/ 40
push const 3 > > = fun () → push const 4 > > = fun () → push const 5 > > = fun () → push const true > > = fun () → i f > > = fun () → add > > = fun () → r e t u r n ()
. . . . . . 3 . . . 3 4 . . . 3 4 5 . . . 3 4 5 T
31/ 40
push const 3 > > = fun () → push const 4 > > = fun () → push const 5 > > = fun () → push const true > > = fun () → i f > > = fun () → add > > = fun () → r e t u r n ()
. . . . . . 3 . . . 3 4 . . . 3 4 5 . . . 3 4 5 T . . . 3 5
31/ 40
push const 3 > > = fun () → push const 4 > > = fun () → push const 5 > > = fun () → push const true > > = fun () → i f > > = fun () → add > > = fun () → r e t u r n ()
. . . . . . 3 . . . 3 4 . . . 3 4 5 . . . 3 4 5 T . . . 3 5 . . . 8
31/ 40
module type STACKA = s i g i n c l u d e PARAMETERISED APPLICATIVE i n c l u d e STACK OPS with type ( ’ s , ’ t , ’ a ) t := ( ’ s , ’ t , ’ a ) t v a l execute : ( ’ s , ’ t , ’ a ) t → ’ s → ’ t end module StackA : STACKA = s t r u c t i n c l u d e Applicative of monad ( StackM ) l e t ( add , i f , push const ) = StackM . ( add , i f , push const ) l e t execute m s = f s t ( StackM . execute m s ) end
32/ 40
pure ( fun () () () () () () → ( ) ) ⊗ push const 3 ⊗ push const 4 ⊗ push const 5 ⊗ push const true ⊗ i f ⊗ add
. . . . . . 3 . . . 3 4 . . . 3 4 5 . . . 3 4 5 T . . . 3 5 . . . 8
33/ 40
PushConst x :: PushConst y :: PushConst true :: If ⇝ PushConst y
. . . . . . x . . . x y . . . x y b . . . y . . . . . . y
34/ 40
l e t rec (++) : type r s t . ( r , s ) i n s t r s → ( s , t ) i n s t r s → ( r , t ) i n s t r s = fun l r → match l with Stop → r | i : : i s → i : : i s ++ r module StackA1 : STACKA = s t r u c t type ( ’ s , ’ t , ’ a ) t = ( ’ s , ’ t ) i n s t r s l e t pure a = Stop l e t (⊗) = (++) l e t add = Add : : Stop l e t i f = I f : : Stop l e t push const v = PushConst v : : Stop l e t execute = (∗ . . . ∗) end
35/ 40
l e t rec
: type s t . ( s , t ) i n s t r s → ( s , t ) i n s t r s = f u n c t i o n [ ] → [ ] | PushConst x : : PushConst y : : PushConst c : : I f : : s →
( PushConst ( i f c then y e l s e x ) : : s ) | i : : i s → i : :
i s
36/ 40
module StackA1 : STACKA = s t r u c t type ( ’ s , ’ t , ’ a ) t = ( ’ s , ’ t ) i n s t r s l e t pure a = Stop l e t (⊗) l r = opt ( l ++ r ) l e t add = Add : : Stop l e t i f = I f : : Stop l e t push const v = PushConst v : : Stop l e t execute = (∗ . . . ∗) end
37/ 40
(;)
38/ 40
module type MONOID = s i g type t v a l zero : t v a l (+ +) : t → t → t end M
1
; M
2
; . . . ; M
n
39/ 40
monads
l e t ! x1 = M
1 in
l e t ! x2 = M
2 in
. . . l e t ! xn = M
n
in N
applicatives
l e t ! x1 = M
1
and ! x2 = M
2
. . . and ! xn = M
n
in N
monoids
M
1
; M
2
; . . . ; M
n
indexed monads and applicatives Γ ⊢ M : A ! e parameterised monads and applicatives {P} C {Q}
40/ 40