last time monads etc
play

Last time: monads (etc.) = > > 1/ 52 This time: arrows, - PowerPoint PPT Presentation

Last time: monads (etc.) = > > 1/ 52 This time: arrows, applicatives (etc.) > > > 2/ 52 Recap: monads, bind and let! An imperative program let id = !counter in let () = counter := id + 1 in string_of_int id A


  1. Last time: monads (etc.) = > > 1/ 52

  2. This time: arrows, applicatives (etc.) > > > ⊗ 2/ 52

  3. Recap: monads, bind and let! An imperative program let id = !counter in let () = counter := id + 1 in string_of_int id A monadic program get = fun id → > > put (id + 1) > = fun () → > return (string_of_int id) 3/ 52

  4. Recap: Type parameters and instantiation parameterised monads monads type (’p, ’q, ’a)t type ’a t { P } C { Q } let .. in 4/ 52

  5. Recap: Higher-order effects with monads val composeM : (’a → ’b t) → (’b → ’c t) → (’a → ’c t) let composeM f g x = = fun y → f x > > g y val uncurryM : (’a → (’b → ’c t) t) → ((’a * ’b) → ’c t) let uncurryM f (x,y) = f x > = fun g → > g y 5/ 52

  6. Applicatives ( let x = e . . . and ) 6/ 52

  7. Allowing only “static” effects Idea: stop information flowing from one computation into another. Only allow unparameterised computations: 1 ⇝ b We can no longer write functions like this: composeE : ( a ⇝ b ) → ( b ⇝ c ) → ( a ⇝ c ) but some useful functions are still possible: pairE static : (1 ⇝ a ) → (1 ⇝ b ) → (1 ⇝ a × b ) 7/ 52

  8. Applicative programs An imperative program let x = fresh_name () and y = fresh_name () in (x, y) An applicative program pure (fun x y → (x, y)) ⊗ fresh_name ⊗ fresh_name 8/ 52

  9. Applicatives module type APPLICATIVE = sig type ’a t val pure : ’a → ’a t val ( ⊗ ) : (’a → ’b) t → ’a t → ’b t end 9/ 52

  10. Applicatives module type APPLICATIVE = sig type ’a t val pure : ’a → ’a t val ( ⊗ ) : (’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 9/ 52

  11. = vs ⊗ > > 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 10/ 52

  12. Applicative normal forms pure f ⊗ c 1 ⊗ c 2 . . . ⊗ c n pure (fun x 1 x 2 . . . x n → e) ⊗ c 1 ⊗ c 2 . . . ⊗ c n let x 1 = c 1 and x 2 = c 2 . . . and x n = c n in e 11/ 52

  13. Applicative normalisation via the laws pure f ⊗ (pure g ⊗ fresh_name ) ⊗ fresh_name 12/ 52

  14. Applicative normalisation via the laws pure f ⊗ (pure g ⊗ fresh_name ) ⊗ fresh_name ≡ (composition law) (pure compose ⊗ pure f ⊗ pure g ⊗ fresh_name ) ⊗ fresh_name 12/ 52

  15. Applicative normalisation via the laws 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 12/ 52

  16. Creating applicatives: every monad is an applicative module Applicative_of_monad (M:MONAD) : APPLICATIVE with type ’a t = ’a M.t = struct type ’a t = ’a M.t let pure = M.return let ( ⊗ ) f p = = fun g → M.(f > > = fun q → p > > return (g q)) end 13/ 52

  17. The state applicative via the state monad module StateA(S : sig type t end) : sig type state = S.t include APPLICATIVE val get : state t val put : state → unit t val runState : ’a t → init:state → state * ’a end = struct type state = S.t include Applicative_of_monad (State(S)) let (get , put , runState) = M.(get , put , runState) end 14/ 52

  18. Creating applicatives: composing applicatives module Compose (F : APPLICATIVE) (G : APPLICATIVE) : APPLICATIVE with type ’a t = ’a G.t F.t = struct type ’a t = ’a G.t F.t let pure x = F.pure (G.pure x) let ( ⊗ ) f x = F.( pure G.( ⊗ ) ⊗ f ⊗ x) end 15/ 52

  19. Creating applicatives: the dual applicative module Dual_applicative (A: APPLICATIVE) : APPLICATIVE with type ’a t = ’a A.t = struct type ’a t = ’a A.t let pure = A.pure let ( ⊗ ) f x = A.( pure (fun y g → g y) ⊗ x ⊗ f) end module RevNameA = Dual_applicative (NameA) RevNameA .( pure (fun x y → (x, y)) ⊗ fresh_name ⊗ fresh_name) 16/ 52

  20. Composed applicatives are law-abiding pure f ⊗ pure x 17/ 52

  21. Composed applicatives are law-abiding pure f ⊗ pure x ≡ (definition of ⊗ and pure) F.pure ( ⊗ G ) ⊗ F F.pure (G.pure f) ⊗ F F.pure (G.pure x) 17/ 52

  22. Composed applicatives are law-abiding 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) 17/ 52

  23. Composed applicatives are law-abiding 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)) 17/ 52

  24. Composed applicatives are law-abiding 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) 17/ 52

  25. Fresh names, monadically type ’a tree = Empty : ’a tree | Tree : ’a tree * ’a * ’a tree → ’a tree module IState = State (struct type t = int end) let fresh_name : string IState.t = = fun i → get > > = fun () → put (i + 1) > > return (Printf.sprintf "x%d" i) let rec label_tree : ’a tree → string tree IState.t = function Empty → return Empty | Tree (l, v, r) → = fun l → label_tree l > > = fun name → fresh_name > > label_tree r > = fun r → > return (Tree (l, name , r)) 18/ 52

  26. Naming as a primitive effect Problem: we cannot write fresh_name using the APPLICATIVE interface. let fresh_name : string IState.t = get = fun i → > > put (i + 1) > = fun () → > return (Printf.sprintf "x%d" i) Solution: introduce it as a primitive effect: module NameA : sig include APPLICATIVE val fresh_name : string t end = . . . 19/ 52

  27. Traversing with namer let rec label_tree : ’a tree → string tree NameA.t = function Empty → pure Empty | Tree (l, v, r) → pure (fun l name r → Tree (l, name , r)) ⊗ label_tree l ⊗ fresh_name ⊗ label_tree r 20/ 52

  28. The phantom monoid applicative module type MONOID = sig type t val zero : t val ( + + ) : t → t → t end module Phantom_monoid (M: MONOID) : APPLICATIVE with type ’a t = M.t = struct type ’a t = M.t let pure _ = M.zero let ( ⊗ ) = M.( + + ) end 21/ 52

  29. The phantom monoid applicative module type MONOID = sig type t val zero : t val ( + + ) : t → t → t end module Phantom_monoid (M: MONOID) : APPLICATIVE with type ’a t = M.t = struct type ’a t = M.t let pure _ = M.zero let ( ⊗ ) = M.( + + ) end Observation: we cannot implement Phantom_monoid as a monad. 21/ 52

  30. Applicatives vs monads programs implementations ⊗ = > > = ⊗ > > Some monadic programs are not applicative, e.g. fresh_name . Some applicative instances are not monadic, e.g. Phantom_monoid . 22/ 52

  31. Guideline: Postel’s law Be conservative in what you do, be liberal in what you accept from others. 23/ 52

  32. Guideline: Postel’s law 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.) 23/ 52

  33. Guideline: Postel’s law 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.) 23/ 52

  34. Parameterised applicatives module type PARAMETERISED_APPLICATIVE = sig type (’s,’t,’a) t val unit : ’a → (’s,’s,’a) t val ( ⊗ ) : (’r,’s,’a → ’b) t → (’s,’t,’a) t → (’r,’t,’b) t end 24/ 52

  35. Stack machines y x . . . 25/ 52

  36. Recap: stack machine instructions c y x y x x+y c (y,x)[c] . . . . . . . . . . . . . . . . . . Add If PushConst 26/ 52

  37. Stack machine operations module type STACK_OPS = sig type (’s,’t,’a) t val add : (int * (int * ’s), int * ’s, unit) t val _if_ : (bool * (’a * (’a * ’s)), ’a * ’s, unit) t val push_const : ’a → (’s, ’a * ’s, unit) t end 27/ 52

  38. Stack machines, monadically module type STACKM = sig include PARAMETERISED_MONAD include STACK_OPS with type (’s,’t,’a) t := (’s,’t,’a) t val execute : (’s,’t,’a) t → ’s → ’t * ’a end module StackM : STACKM = struct include PState = fun (x,(y,s)) → put (x+y,s) let add = get > > = let _if_ = get (c,(t,(e,s))) > > put (if c then t else e) = fun s → put (k, s) let push_const k = get > > let execute = runState end 28/ 52

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend