tim sheard oregon graduate institute lecture 6: monads and interpreters cse 510 section fsc winter...
Post on 20-Dec-2015
219 views
TRANSCRIPT
Tim SheardOregon Graduate Institute
Lecture 6: Monads and Interpreters
CSE 510 Section FSCCSE 510 Section FSC
Winter 2004Winter 2004
2Cs510 FSC Winter 2005
Interpreters are hard to modify
Consider the interpreters for Exp and ComConsider 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.
3Cs510 FSC Winter 2005
Extended Abstract Syntaxdatatype 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) *)
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
5Cs510 FSC Winter 2005
New interp functionfun 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
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
7Cs510 FSC Winter 2005
Add Divide and error catching
New types eval2 : Exp -> env -> int option interp2 : Com -> env -> env option
WhereDatatype ‘a option = NONE | SOME of ‘a
8Cs510 FSC Winter 2005
Eval2fun 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) | _ => 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) | _ => NONE)
Error production
Error propagation
9Cs510 FSC Winter 2005
interp2fun 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. *)
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
11Cs510 FSC Winter 2005
Eval3fun 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
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
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
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
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;
16Cs510 FSC Winter 2005
Error Monaddatatype ‘a option = NONE | SOME of
fun return x = SOME x;
fun bind (SOME x) g = g x
| bind NONE g = NONE;
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;
18Cs510 FSC Winter 2005
Monads in Meta MLMonads are built into MetaMLUsers can define their own MonadsMonads support their own special syntax Do m { x <- e; y } === bind e (fn 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
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))));
20Cs510 FSC Winter 2005
Polymorphic Componentsdatatype 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 )
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 = []}
22Cs510 FSC Winter 2005
Pattern Matching to accessfun 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 )
23Cs510 FSC Winter 2005
MonadsA 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
24Cs510 FSC Winter 2005
Instances of Monad Actions
Performing input/outputChanging the value of a mutable variableRaising 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
25Cs510 FSC Winter 2005
The standard morphisms
Return : creates a simple (nullary) action which does nothingBind: sequences two actions
Non-standard morphisms describe the actions of the monad
26Cs510 FSC Winter 2005
Monads in MetaMLUses 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;
27Cs510 FSC Winter 2005
Do and ReturnMetaML’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));
28Cs510 FSC Winter 2005
Syntactic SugarDo (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 }}}
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);
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;
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;
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) }
33Cs510 FSC Winter 2005
Examplesval 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
34Cs510 FSC Winter 2005
Interp, one more timefun 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) } ;
35Cs510 FSC Winter 2005
All features at once
Now making an interpreter with all the features is easyDefine a new monad with all the featuresAdd a few new cases for Print and DivideWrite a few non-standard morphisms Inject some new output for print Raise an error for divide by zero
36Cs510 FSC Winter 2005
New Monaddatatype '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);
37Cs510 FSC Winter 2005
Non-Standard morphisms
fun output s = M(SOME[s],s);
fun fail s = M(NONE,s);
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) }
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
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 }