Download presentation
Presentation is loading. Please wait.
1
Tim Sheard Oregon Graduate Institute Lecture 6: Monads and Interpreters CSE 510 Section FSC Winter 2004 Winter 2004
2
2Cs510 FSC Winter 2005 Interpreters are hard to modify Consider the interpreters for Exp and Com Consider 3 extensions Adding a print command Adding a divide expression and catching divide by 0 errors Adding a notion of multiple results Drastic changes need to be made to the structure of the interpreter.
3
3Cs510 FSC Winter 2005 Extended Abstract Syntax datatype Exp = Constant of int (* 5 *) | Variable of string (* x *) | Minus of (Exp * Exp) (* x - 5 *) | Greater of (Exp * Exp) (* x > 1 *) | Times of (Exp * Exp) (* x * 4 *) | Divide of (Exp * Exp) (* x / 3 *) datatype Com = Assign of (string * Exp) (* x := 1 *) | Seq of (Com * Com) (* { x := 1; y := 2 } *) | If of (Exp * Com * Com) (* if x then x := 1 else y := 1 *) | While of (Exp * Com) (* while x>0 do x := x - 1 *) | Declare of (string * Exp * Com) (* Declare x = 1 in x := x - 1 *) | Print of string * Exp (* Print "answer" (x+2) *)
4
4Cs510 FSC Winter 2005 Adding a Print command New types type env = (string * int) list eval0 : Exp -> env -> int interp1 : Com -> env -> (env * string) The type of Eval doesn’t change since evaluation of Exp can’t cause any printing. A Com is an env transformer and an output producer. String produced by printing
5
5Cs510 FSC Winter 2005 New interp function fun interp1 stmt env = case stmt of Assign(name,e) => let val v = eval0 e env in (set name v env,"") end | Seq(x1,x2) => let val (env1,s1) = interp1 x1 env val (env2,s2) = interp1 x2 env1 in (env2,s1 ^ s2) end | If(e,s1,s2) => let val x = eval0 e env in if x=1 then interp1 s1 env else interp1 s2 env end Assignment cause no output Collect output from both sub-commands
6
6Cs510 FSC Winter 2005 Interp continued | While(e,body) => let fun loop env s = let val v = eval0 e env in if v=0 then (env,s) else let val (env1,s1) = interp1 body env in loop env1 (s^s1) end end in loop env "" end | Declare(nm,e,stmt) => let val v = eval0 e env val env1 = ext nm v env val (env2,s) = interp1 stmt env1 in (remove env2,s) end; Output collected from many traversals of loop Env is shrunk but output is propagated
7
7Cs510 FSC Winter 2005 Add Divide and error catching New types eval2 : Exp -> env -> int option interp2 : Com -> env -> env option Where Datatype ‘a option = NONE | SOME of ‘a
8
8Cs510 FSC Winter 2005 Eval2 fun eval2 exp env = case exp of Constant n => SOME n | Variable s => SOME (lookup s env) | Minus(x,y) => (case eval2 x env of SOME a => (case eval2 y env of SOME b => SOME(a - b) | _ => NONE) |... (* similar for Greter and Times *) | Divide(x,y) => (case eval2 x env of SOME a => (case eval2 y env of SOME 0 => NONE | SOME b => SOME(a div b) | _ => NONE) Error production Error propagation
9
9Cs510 FSC Winter 2005 interp2 fun interp2 stmt env = case stmt of Assign(name,e) => (case eval2 e env of SOME v => SOME(set name v env) | _ => NONE) | Seq(s1,s2) => (case interp2 s1 env of SOME env1 => interp2 s2 env1 | NONE => NONE) | If(e,s1,s2) => (case eval2 e env of SOME x => if x=1 then interp2 s1 env else interp2 s2 env | NONE => NONE) |... (* similar for While etc. *)
10
10Cs510 FSC Winter 2005 Additions for multiple values E.g. Suppose x [9,5] y [2,4] Then (x – y) [7,5,3,1] [9-2, 9-4, 5-2, 5-4] New types type env = (string * int list) list; eval3 : Exp -> env -> int list Interp3 : Com -> env -> env Useful function – combines map and append fun mapp f [] = [] | mapp f (x::xs) = (f x) @ (mapp f xs); Appends results rather than consing them
11
11Cs510 FSC Winter 2005 Eval3 fun eval3 exp env = case exp of Constant n => [n] | Variable s => lookup s env | Minus(x,y) => let val xs = eval3 x env fun f x = let val ys = eval3 y env fun g y = [x - y] in mapp g ys end in mapp f xs end | Greater(x,y) => let val xs = eval3 x env fun f x = let val ys = eval3 y env fun g y = [ if x '>' y then 1 else 0] in mapp g ys end in mapp f xs end |... Constants have singleton values Recursive calls give multiple results which are then combined
12
12Cs510 FSC Winter 2005 Example run val env3 = [("x",[9,5]),("y",[2,4])] val test2 = eval3 (Minus (Variable "x",Variable "y")) env3; -| test2; val it = [7,5,3,1] : int list
13
13Cs510 FSC Winter 2005 Notes Each new addition made drastic changes to the structure of the code. Print – extra results returned in pair Divide – case analysis to determine if SOME or NONE Mulitiple Answers – results are lists, need complicated use of mapp to combine results Consider making an interpreter with all three changes
14
14Cs510 FSC Winter 2005 Patterns (x,””)SOME x[x] Let val (a,s) = e1 val (b,t) = e2 In f[s^t] Case e of SOME z => m NONE => NONE Let val xs = e fun f x = … In mapp f xs end These patterns can be captured by two functions Return : ‘a -> ‘a M Bind : ‘a M -> (‘a -> ‘b M) -> ‘b M Where M is some type constructor. This pattern is called a Monad ‘a M = (‘a * string) ‘a M = ‘a option ‘a M = ‘a list
15
15Cs510 FSC Winter 2005 Output monad fun return x = (x,""); fun bind (x,s1) g = let val (y,s2) = g x in (y,s1^s2) end;
16
16Cs510 FSC Winter 2005 Error Monad datatype ‘a option = NONE | SOME of fun return x = SOME x; fun bind (SOME x) g = g x | bind NONE g = NONE;
17
17Cs510 FSC Winter 2005 Monad of Multiple results datatype ‘a list = [] | ‘a :: ‘a list; fun return x = [x]; fun bind xs g = mapp g xs;
18
18Cs510 FSC Winter 2005 Monads in Meta ML Monads are built into MetaML Users can define their own Monads Monads support their own special syntax Do m { x y) Return m x === return x Monads require extensions to ML Higher order type constructors Type constructors (I.e. things like list) which take type constructors as arguments Polymorphic components to records
19
19Cs510 FSC Winter 2005 Higher Order Type Constructors datatype ('a,'T : * -> * ) tree = Tip of 'a | Node of (('a,'T)tree) 'T; datatype 'a binary = bin of 'a * 'a; val z: (int,list) tree = Node [ Tip 4, Tip 2 ]; val w: (int,binary ) tree = Node(bin (Tip 1,Node(bin (Tip 3, Tip 0))));
20
20Cs510 FSC Winter 2005 Polymorphic Components datatype a = A of (['a].'a list -> 'a list); fun copy [] = [] | copy (x::xs) = x :: (copy xs); val a1 = A(rev); val a2 = A copy; -| fun f x y (A g) = (g x, g y); val f = Fn : ['a,'b].'b list -> 'a list -> a -> ('b list * 'a list ) -| val q = f [1,2,3] ["x","y","d"] a1; val q = ([3,2,1],["d","y","x"]) : (int list * string list )
21
21Cs510 FSC Winter 2005 List Monoid example datatype list_monoid = LM of { inject : ['a].'a -> 'a list, plus : ['a]. 'a list -> 'a list -> 'a list, zero : ['a].'a list }; val lm1 = LM{inject = fn x => [x], plus = fn x => fn y => x@y, zero = []}
22
22Cs510 FSC Winter 2005 Pattern Matching to access fun f (LM{inject=inj, plus = sum, zero = z}) = (sum z (inj 2), sum (inj true) (inj false)); -| f lm1; val it = ([2],[true,false ]) : (int list * bool list )
23
23Cs510 FSC Winter 2005 Monads A Monad is A type constructor T a type to type function and 2 polymorphic functions unit : ‘a -> ‘a T bind: (‘a T) -> (‘a -> ‘b T) -> (‘b T) an expression with type ‘a T is a computation returns a value of type ‘a might perform a T action Print, propogate errors, return multiple results
24
24Cs510 FSC Winter 2005 Instances of Monad Actions Performing input/output Changing the value of a mutable variable Raising an exception Monads can be “emulated” with pure functional programs by threading stores, or I/O streams, or exception continuations in and out of all computations
25
25Cs510 FSC Winter 2005 The standard morphisms Return : creates a simple (nullary) action which does nothing Bind: sequences two actions Non-standard morphisms describe the actions of the monad
26
26Cs510 FSC Winter 2005 Monads in MetaML Uses both HHTC and local polymorphism datatype ('m : * -> * ) monad = Mon of (['a]. 'a -> 'a 'm) * (['a,'b]. ('a 'm) -> ('a -> 'b 'm) -> 'b 'm); type 'x Id = 'x; val Id = (Mon (fn x => x, fn x => fn f => f x)) : Id Monad;
27
27Cs510 FSC Winter 2005 Do and Return MetaML’s interface to the standard morphisms unit and bind val ex = let fun bind (SOME x) f = f x | bind NONE f = NONE in (Mon(SOME,bind)) : option Monad end; fun option f x = Do ex { z <- x ; Return ex (f z) }; vs fun option f x = bind x (fn z => unit (f z));
28
28Cs510 FSC Winter 2005 Syntactic Sugar Do (Mon(unit,bind)) { x <- e; f } = bind e (fn x => f) Return (Mon(unit,bind)) e = unit e Do m { x1 <- e1; x2 <- e2 ; x3 <- e3 ; e4 } = Do m { x1 <- e1; Do m { x2 <- e2 ; Do m { x3 <- e3 ; e4 }}}
29
29Cs510 FSC Winter 2005 Output Monad again datatype 'a OP = OP of 'a * string; fun return x = OP(x,""); fun bind (OP(x,s1)) g = let val OP(y,s2) = g x in OP(y,s1^s2) end; val om = Mon(return,bind);
30
30Cs510 FSC Winter 2005 Error (option) Monad again val em = let fun return x = SOME x; fun bind (SOME x) g = g x | bind NONE g = NONE; in Mon(return,bind) end;
31
31Cs510 FSC Winter 2005 Multiple values (list) Monad again val mvm = let fun return x = [x]; fun mapp f [] = [] | mapp f (x::xs) = (f x) @ (mapp f xs); fun bind xs g = mapp g xs; in Mon(return,bind) end;
32
32Cs510 FSC Winter 2005 The interpreter one more time (* eval4: ‘m Monad -> Exp -> (string * int ‘m ) list -> int ‘m *) fun eval4 m exp env = case exp of Constant n => Return m n | Variable s => lookup s env | Minus(x,y) => Do m { a <- eval4 m x env ; b <- eval4 m y env ; Return m (a - b) } | Greater(x,y) => Do m { a <- eval4 m x env ; b <- eval4 m y env ; Return m (if a '>' b then 1 else 0) } | Times(x,y) => Do m { a <- eval4 m x env ; b <- eval4 m y env ; Return m (a * b) }
33
33Cs510 FSC Winter 2005 Examples val term = (Minus (Variable "x",Variable "y")) val envMVM = [("x",[9,5]),("y",[2,4])] val ans1 = eval4 mvm term envMVM; val it = [7,5,3,1] : int list val envEM = [("x",SOME 4),("y",SOME 2)] val ans2 = eval4 em term envEM; val it = SOME 2 : int option
34
34Cs510 FSC Winter 2005 Interp, one more time fun interp4 m stmt env = case stmt of Assign(name,e) => Do m { v <- eval4 m e env ; Return m(set name (Return m v) env) } | Seq(s1,s2) => Do m { env1 <- interp4 m s1 env ; interp4 m s2 env1 } | If(e,s1,s2) => Do m { x <- eval4 m e env ; if x=1 then interp4 m s1 env else interp4 m s2 env } | While(e,body) => let fun loop env = Do m { v <- eval4 m e env ; if v=0 then Return m env else Do m { env1 <- interp4 m body env; loop env1 }} in loop env end | Declare(nm,e,stmt) => Do m { v <- eval4 m e env ; env2 <- interp4 m stmt (ext nm (Return m v) env) ; Return m (remove env2) } ;
35
35Cs510 FSC Winter 2005 All features at once Now making an interpreter with all the features is easy Define a new monad with all the features Add a few new cases for Print and Divide Write a few non-standard morphisms Inject some new output for print Raise an error for divide by zero
36
36Cs510 FSC Winter 2005 New Monad datatype 'a M = M of (('a list) option) * string; fun return x = M(SOME[x],""); fun mapp f [] = M(SOME[],"") | mapp f (x::xs) = (case f x of M(NONE,s) => M(NONE,s) | M(SOME ys,s1) => (case mapp f xs of M(SOME zs,s2) => M(SOME(ys @ zs),s1^s2) | M(NONE,s2) => M(NONE,s1^s2))) fun bind (M(NONE,s)) g = M(NONE,s) | bind (M(SOME xs,s1)) g = let val M(zs,s2) = mapp g xs in M(zs,s1^s2) end val m = Mon(return,bind);
37
37Cs510 FSC Winter 2005 Non-Standard morphisms fun output s = M(SOME[s],s); fun fail s = M(NONE,s);
38
38Cs510 FSC Winter 2005 Ultimate interpreter (* eval5 : Exp -> (string * int M) list -> int M *) fun eval5 exp env = case exp of Constant n => Return m n | Variable s => lookup s env | Minus(x,y) => Do m { a <- eval5 x env ; b <- eval5 y env ; Return m (a - b) } | Greater(x,y) => Do m { a <- eval5 x env ; b <- eval5 y env ; Return m (if a '>' b then 1 else 0)} | Times(x,y) => Do m { a <- eval5 x env ; b <- eval5 y env ; Return m (a * b) } | Divide(x,y) => Do m { a <- eval5 x env ; b <- eval5 y env ; if b = 0 then fail "Divide by 0" else Return m (a div b) }
39
39Cs510 FSC Winter 2005 interp5 (* interp5 : Com -> (string * int M) list -> (string * int M) list M *) fun interp5 stmt env = case stmt of Assign(name,e) => Do m { v <- eval5 e env; Return m(set name (Return m v) env) } | Seq(s1,s2) => Do m { env1 <- interp5 s1 env; interp5 s2 env1 } | If(e,s1,s2) => Do m { x <- eval5 e env ; if x=1 then interp5 s1 env else interp5 s2 env } | While(e,body) => let fun loop env = Do m { v <- eval5 e env ; if v=0 then Return m env else Do m { env1 <- interp5 body env ; loop env1 }} in loop env end
40
40Cs510 FSC Winter 2005 Interp5 continued (* interp5 : Com -> (string * int M) list -> (string * int M) list M *) fun interp5 stmt env = case stmt of... | Declare(nm,e,stmt) => Do m { v <- eval5 e env ; env2 <- interp5 stmt (ext nm (Return m v) env) ; Return m (remove env2) } | Print(s,e) => Do m { v <- eval5 e env ; output (s^" "^(show v)) ; Return m env }
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.