An OCaml definion of OCaml evaluaon, or,
Transcript of An OCaml definion of OCaml evaluaon, or,
Implemen'ngOCamlinOCaml
AnOCamldefini'onofOCamlevalua'on,or,
COS326DavidWalker
PrincetonUniversityslidescopyright2013-2015DavidWalkerandAndrewW.Appel
permissiongrantedtoreusetheseslidesfornon-commercialeduca'onalpurposes
1
Implemen'nganInterpreter
letx=3inx+x
Let(“x”,Num3,Binop(Plus,Var“x”,Var“x”))
Num6
6
Parsing
Evalua'on
PreWyPrin'ng
textfilecontainingprogramasasequenceofcharacters
datastructurerepresen'ngprogram
datastructurerepresen'ngresultofevalua'on
textfile/stdoutcontainingwithformaWedoutput
thedatatypeandevaluatortellusalotaboutprogramseman'cs
2
WecandefineadatatypeforsimpleOCamlexpressions:
type variable = string
type op = Plus | Minus | Times | … type exp = | Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp type value = exp
MakingTheseIdeasPrecise 3
MakingTheseIdeasPrecise 4
WecandefineadatatypeforsimpleOCamlexpressions:
type variable = string type op = Plus | Minus | Times | … type exp = | Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp type value = exp let e1 = Int_e 3 let e2 = Int_e 17 let e3 = Op_e (e1, Plus, e2)
represents“3+17”
MakingTheseIdeasPrecise 5
WecanrepresenttheOCamlprogram:
let x = 30 in let y = (let z = 3 in z*4) in y+y;;
asanexpvalue:
Let_e(“x”, Int_e 30, Let_e(“y”, Let_e(“z”, Int_e 3, Op_e(Var_e “z”, Times, Int_e 4)), Op_e(Var_e “y”, Plus, Var_e “y”)
MakingTheseIdeasPrecise 6
No'cehowthisreflectsthe“tree”:Let_e(“x”,Int_e 30,
Let_e(“y”,Let_e(“z”,Int_e 3,
Op_e(Var_e “z”, Times, Int_e 4)),
Op_e(Var_e “y”, Plus, Var_e “y”)
let
x 30 let
y let +
z 3 *y y
z 4
Bindingoccurrencesversusappliedoccurrences 7
type exp = | Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp
Thisisabindingoccurrenceofavariable
Thisisauseofavariable
let is_value (e:exp) : bool = match e with | Int_e _ -> true | ( Op_e _ | Let_e _ | Var_e _ ) -> false
eval_op : value -> op -> value -> exp
(* substitute v x e:replace free occurrences of x with v in e *)
substitute : value -> variable -> exp -> exp
SomeUsefulAuxiliaryFunc'ons 8
nested“|”paWern(can’tusevariables)
ASimpleEvaluator 9
is_value : exp -> booleval_op : value -> op -> value -> valuesubstitute : value -> variable -> exp -> exp
let rec eval (e:exp) : exp = match e with | Int_e i -> | Op_e(e1,op,e2) ->
| Let_e(x,e1,e2) ->
ASimpleEvaluator 10
is_value : exp -> booleval_op : value -> op -> value -> valuesubstitute : value -> variable -> exp -> exp
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) ->
| Let_e(x,e1,e2) ->
is_value : exp -> booleval_op : value -> op -> value -> valuesubstitute : value -> variable -> exp -> exp
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) ->
let v1 = eval e1 in let v2 = eval e2 in
eval_op v1 op v2 | Let_e(x,e1,e2) ->
ASimpleEvaluator 11
ASimpleEvaluator 12
is_value : exp -> booleval_op : value -> op -> value -> valuesubstitute : value -> variable -> exp -> exp
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) ->
let v1 = eval e1 in let v2 = eval e2 in
eval_op v1 op v2 | Let_e(x,e1,e2) -> let v1 = eval e1 in let e2’ = substitute v1 x e2 in
eval e2’
ShorterbutDangerous 13
Why?
is_value : exp -> booleval_op : value -> op -> value -> valuesubstitute : value -> variable -> exp -> exp
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) ->
eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) ->
eval (substitute (eval e1) x e2)
is_value : exp -> booleval_op : value -> op -> value -> valuesubstitute : value -> variable -> exp -> exp
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) ->
eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) ->
eval (substitute (eval e1) x e2)
SimplerbutDangerous
Whichgetsevaluatedfirst?DoesOCamluselei-to-rightevalorderorright-to-lei?AlwaysuseOCamlletifyouwanttospecifyevalua'onorder.
14
is_value : exp -> booleval_op : value -> op -> value -> valuesubstitute : value -> variable -> exp -> exp
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) ->
eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) ->
eval (substitute (eval e1) x e2)
SimplerbutDangerous
Sincethelanguageweareinterpre'ngispure(noeffects),itwon’tmaWerwhichexpressiongetsevaluatedfirst.We’llproducethesameanswerineithercase.
15
Limita'onsofmetacircularinterpreters 16
is_value : exp -> booleval_op : value -> op -> value -> valuesubstitute : value -> variable -> exp -> exp
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) ->
let v1 = eval e1 in let v2 = eval e2 in
eval_op v1 op v2 | Let_e(x,e1,e2) -> let v1 = eval e1 in let e2’ = substitute v1 x e2 in
eval e2’
Whichgetsevaluatedfirst,(evale1)or(evale2)?Seemsobvious,right?
Butthat’sbecauseweassumeOCamlhascall-by-valueevalua'on!Ifitwerecall-by-name,thenthisorderingofletswouldnotguaranteeorder
ofevalua'on.
Moral:usingalanguagetodefineitsownseman+cscanhavelimita6ons.
Backtotheevalfunc'on… 17
let eval_op v1 op v2 = …let substitute v x e = …
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2)
(sameastheoneacoupleofslidesago)
Oops!WeMissedaCase: 18
let eval_op v1 op v2 = …let substitute v x e = …
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> ???
Weshouldneverencounteravariable–theyshouldhavebeensubs'tutedwithavalue!(Thisisatype-error.)Wecouldleaveoutthecaseforvariablesifwetypecheckbeforeevalua+ng.(whichweshoulddefinitelydo!)ButthatwillcreateamessofOcamlwarnings–badstyle.(Badfordebugging.)
WeCouldUseOp'ons: 19
let eval_op v1 op v2 = …let substitute v x e = …
let rec eval (e:exp) : exp option = match e with | Int_e i -> Some(Int_e i) | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> None
Butthisisn’tquiteright–weneedtomatchontherecursivecallstoevaltomakesurewegetSomevalue!
Excep'ons 20
exception UnboundVariable of variable
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x)
Instead,wecanthrowanexcep'on.
Excep'ons 21
Notethatanexcep'ondeclara'onisalotlikeadatatypedeclara'on.Really,weareextendingonebigdatatype(exn)withanewconstructor(UnboundVariable).
exception UnboundVariable of variable
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x)
Lateron,we’llseehowtocatchanexcep'on.
Excep'onorop'on?Inapreviouslecture,Iexplainedwhytouseanop'ontype(oraSuccess/Failuredatatype)insteadofraisinganexcep'on.
No!Idonotcontradictmyself!• Theotherexamplewasforerrorsthatwilloccur
(becausetheinputmightbeillformaWed).• Thisexampleisforerrorsthatcannotoccur
(unlesstheprogramitselfhasabug).
22
AUXILIARYFUNCTIONS
23
Evalua'ngthePrimi'veOpera'ons 24
let eval_op (v1:exp) (op:operand) (v2:exp) : exp = match v1, op, v2 with | Int_e i, Plus, Int_e j -> Int_e (i+j) | Int_e i, Minus, Int_e j -> Int_e (i-j) | Int_e i, Times, Int_e j -> Int_e (i*j) | _ ,(Plus | Minus | Times), _ ->
if is_value v1 && is_value v2 then raise TypeError else raise NotValue
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) ;;
Subs'tu'on
25
let substitute (v:exp) (x:variable) (e:exp) : exp =
...
;;
Wanttoreplacex(andonlyx)withv.
Subs'tu'on
26
let substitute (v:exp) (x:variable) (e:exp) : exp = let rec subst (e:exp) : exp = match e with | Int_e _ -> | Op_e(e1,op,e2) -> | Var_e y -> ... use x ... | Let_e (y,e1,e2) -> ... use x ...
in subst e ;;
Subs'tu'on
27
let substitute (v:exp) (x:variable) (e:exp) : exp = let rec subst (e:exp) : exp = match e with | Int_e _ -> e | Op_e(e1,op,e2) -> | Var_e y -> | Let_e (y,e1,e2) ->
in subst e ;;
Subs'tu'on
28
let substitute (v:exp) (x:variable) (e:exp) : exp = let rec subst (e:exp) : exp = match e with | Int_e _ -> e | Op_e(e1,op,e2) -> Op_e(subst e1,op,subst e2) | Var_e y -> | Let_e (y,e1,e2) ->
in subst e ;;
Subs'tu'on
29
let substitute (v:exp) (x:variable) (e:exp) : exp = let rec subst (e:exp) : exp = match e with | Int_e _ -> e | Op_e(e1,op,e2) -> Op_e(subst e1,op,subst e2) | Var_e y -> if x = y then v else e | Let_e (y,e1,e2) ->
in subst e ;;
Subs'tu'on
30
let substitute (v:exp) (x:variable) (e:exp) : exp = let rec subst (e:exp) : exp = match e with | Int_e _ -> e | Op_e(e1,op,e2) -> Op_e(subst e1,op,subst e2) | Var_e y -> if x = y then v else e | Let_e (y,e1,e2) -> Let_e (y, subst e1, subst e2) in subst e ;;
WRONG!
Subs'tu'on
31
let substitute (v:exp) (x:variable) (e:exp) : exp = let rec subst (e:exp) : exp = match e with | Int_e _ -> e | Op_e(e1,op,e2) -> Op_e(subst e1,op,subst e2) | Var_e y -> if x = y then v else e | Let_e (y,e1,e2) -> Let_e (y, if x = y then e1 else subst e1, if x = y then e2 else subst e2) in subst e ;;
wrong
Subs'tu'on
32
let substitute (v:exp) (x:variable) (e:exp) : exp = let rec subst (e:exp) : exp = match e with | Int_e _ -> e | Op_e(e1,op,e2) -> Op_e(subst e1,op,subst e2) | Var_e y -> if x = y then v else e | Let_e (y,e1,e2) -> Let_e (y, subst e1, if x = y then e2 else subst e2) in subst e ;;
evalua'on/subsitu'onmustimplementourvariablescopingrulescorrectly
Subs'tu'on
33
let substitute (v:exp) (x:variable) (e:exp) : exp = let rec subst (e:exp) : exp = match e with | Int_e _ -> e | Op_e(e1,op,e2) -> Op_e(subst e1,op,subst e2) | Var_e y -> if x = y then v else e | Let_e (y,e1,e2) -> Let_e (y, subst e1, if x = y then e2 else subst e2) in subst e ;; Ifxandyare
thesamevariable,thenyshadowsx.
SCALINGUPTHELANGUAGE(MOREFEATURES,MOREFUN)
34
ScalinguptheLanguage 35
type exp = Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp | Fun_e of variable * exp | FunCall_e of exp * exp ;;
ScalinguptheLanguage 36
type exp = Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp | Fun_e of variable * exp | FunCall_e of exp * exp ;;
OCaml’sfunx->e
isrepresentedasFun_e(x,e)
ScalinguptheLanguage 37
type exp = Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp | Fun_e of variable * exp | FunCall_e of exp * exp ;;
Afunc'oncallfact3
isimplementedasFunCall_e(Var_e“fact”,Int_e3)
ScalinguptheLanguage 38
type exp = Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp | Fun_e of variable * exp | FunCall_e of exp * exp;;
let is_value (e:exp) : bool = match e with | Int_e _ -> true | Fun_e (_,_) -> true | ( Op_e (_,_,_) | Let_e (_,_,_) | Var_e _ | FunCall_e (_,_) ) -> false ;;
Func'onsarevalues!
Easyexamques'on:WhatvaluedoestheOCamlinterpreterproducewhenyouenter(funx->3)intotheprompt?Answer:thevalueproducedis(funx->3)
ScalinguptheLanguage: 39
type exp = Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp | Fun_e of variable * exp | FunCall_e of exp * exp;;
let is_value (e:exp) : bool = match e with | Int_e _ -> true | Fun_e (_,_) -> true | ( Op_e (_,_,_) | Let_e (_,_,_) | Var_e _ | FunCall_e (_,_) ) -> false ;;
Func'oncallsarenotvalues.
ScalinguptheLanguage: 40
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1, eval e2 with | Fun_e (x,e), v2 -> eval (substitute v2 x e) | _ -> raise TypeError)
ScalinguptheLanguage: 41
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1, eval e2 with | Fun_e (x,e), v2 -> eval (substitute v2 x e) | _ -> raise TypeError)
values(includingfunc'ons)always
evaluatetothemselves.
ScalinguptheLanguage: 42
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1, eval e2 with | Fun_e (x,e), v2 -> eval (substitute v2 x e) | _ -> raise TypeError)
Toevaluateafunc'oncall,wefirstevaluate
bothe1ande2tovalues.
ScalinguptheLanguage 43
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1, eval e2 with | Fun_e (x,e), v2 -> eval (substitute v2 x e) | _ -> raise TypeError)
e1hadbeWerevaluatetoafunc'onvalue,elsewehaveatypeerror.
ScalinguptheLanguage 44
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1, eval e2 with | Fun_e (x,e), v2 -> eval (substitute v2 x e) | _ -> raise TypeError)
Thenwesubs'tutee2’svalue(v2)forxineandevaluatetheresul'ng
expression.
SimplifyingaliWle 45
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1 | Fun_e (x,e) -> eval (substitute (eval e2) x e) | _ -> raise TypeError)
Wedon’treallyneedtopaWern-matchone2.
Justevaluatehere
SimplifyingaliWle 46
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (ef,e1) -> (match eval ef with | Fun_e (x,e2) -> eval (substitute (eval e1) x e2) | _ -> raise TypeError)
Thislookslikethecaseforlet!
LetandLambda 47
let x = 1 in x+41 -->1+41-->42
Ingeneral:
(fun x -> x+41) 1-->1+41-->42
(fun x -> e2) e1 == let x = e1 in e2
Sowecouldwrite: 48
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (FunCall (Fun_e (x,e2), e1)) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (ef,e2) -> (match eval ef with | Fun_e (x,e1) -> eval (substitute (eval e1) x e2) | _ -> raise TypeError)
Inprogramming-languagesspeak:“Letissyntac6csugarforafunc'oncall”Syntac'csugar:Anewfeaturedefinedbyasimple,localtransforma'on.
Recursivedefini'ons 49
type exp = Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp | | Fun_e of variable * exp | FunCall_e of exp * exp | Rec_e of variable * variable * exp ;;
let rec f x = f (x+1) in f 3
Let_e (“g, Rec_e (“f”, “x”, FunCall_e (Var_e “f”, Op_e (Var_e “x”, Plus, Int_e 1)) ), FunCall (Var_e “g”, Int_e 3))
(rewrite)
(alpha-convert)let f = (rec f x -> f (x+1)) inf 3
let g = (rec f x -> f (x+1)) ing 3
(implement)
Recursivedefini'ons 50
type exp = Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp | | Fun_e of variable * exp | FunCall_e of exp * exp | Rec_e of variable * variable * exp ;;
let is_value (e:exp) : bool = match e with | Int_e _ -> true | Fun_e (_,_) -> true | Rec_e of (_,_,_) -> true | (Op_e (_,_,_) | Let_e (_,_,_) | Var_e _ | FunCall_e (_,_) ) -> false ;;
Recursivedefini'ons 51
type exp = Int_e of int | Op_e of exp * op * exp | Var_e of variable | Let_e of variable * exp * exp | | Fun_e of variable * exp | FunCall_e of exp * exp | Rec_e of variable * variable * exp ;;
let is_value (e:exp) : bool = match e with | Int_e _ -> true | Fun_e (_,_) -> true | Rec_e of (_,_,_) -> true | (Op_e (_,_,_) | Let_e (_,_,_) | Var_e _ | FunCall_e (_,_) ) -> false ;; Fun_e(x,body)==Rec_e("unused",x,body)
AbeWerIRwouldjustdeleteFun_e–avoid
unnecessaryredundancy
Interlude:Nota'onforSubs'tu'on
“Subs'tutevaluevforvariablexinexpressione:” e[v/x]
(x+y)[7/y] is (x+7)(letx=30inlety=40inx+y)[7/y]is(letx=30inlety=40inx+y)(lety=yinlety=yiny+y)[7/y] is (lety=7inlety=yiny+y)
examplesofsubs'tu'on:
52
Evalua'ngRecursiveFunc'ons 53
Basicevalua'onruleforrecursivefunc'ons:
(recfx=body)arg-->body[arg/x][recfx=body/f]
en'refunc'onsubs'tutedforfunc'onname
argumentvaluesubs'tutedforparameter
Evalua'ngRecursiveFunc'ons 54
let g = rec f x -> if x <= 0 then x else x + f (x-1) in g 3
Startoutwithaletboundtoarecursivefunc'on:
TheSubs'tu'on:g 3 [rec f x -> if x <= 0 then x else x + f (x-1) / g]
TheResult: (rec f x -> if x <= 0 then x else x + f (x-1)) 3
Evalua'ngRecursiveFunc'ons
55
RecursiveFunc'onCall:
TheSubs'tu'on:
TheResult:
(if x <= 0 then x else x + f (x-1)) [ rec f x -> if x <= 0 then x else x + f (x-1) / f ] [ 3 / x ]
(rec f x -> if x <= 0 then x else x + f (x-1)) 3
(if 3 <= 0 then 3 else 3 + (rec f x -> if x <= 0 then x else x + f (x-1)) (3-1))
Subs'tuteen'refunc'onforfunc'onname
Subs'tuteargumentforparameter
Evalua'ngRecursiveFunc'ons 56
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i | Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x) | Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1 with | Fun_e (x,e) ->
let v = eval e2 in substitute e x v
| (Rec_e (f,x,e)) as f_val -> let v = eval e2 in substitute f_val f (substitute v x e)
| _ -> raise TypeError)
pa=ernasxmatchthepaWernandbindsxtovalue
MoreEvalua'on 57
(rec fact n = if n <= 1 then 1 else n * fact(n-1)) 3-->if 3 < 1 then 1 else 3 * (rec fact n = if ... then ... else ...) (3-1)-->3 * (rec fact n = if … ) (3-1)-->3 * (rec fact n = if … ) 2-->3 * (if 2 <= 1 then 1 else 2 * (rec fact n = ...)(2-1))-->3 * (2 * (rec fact n = ...)(2-1))-->3 * (2 * (rec fact n = ...)(1))-->3 * 2 * (if 1 <= 1 then 1 else 1 * (rec fact ...)(1-1))-->3 * 2 * 1
AMATHEMATICALDEFINITION*OFOCAMLEVALUATION
*it’sapar'aldefini'onandthisisabigtopic;formore,seeCOS510
58
FromCodetoAbstractSpecifica'on
OCamlcodecangivealanguageseman'cs– advantage:itcanbeexecuted,sowecantryitout– advantage:itisamazinglyconcise
• especiallycomparedtowhatyouwouldhavewriWeninJava– disadvantage:itisaliWleuglytooperateoverconcreteMLdatatypeslike“Op_e(e1,Plus,e2)”asopposedto“e1+e2”
– disadvantage:definingalanguageinitselfisalogicalfallacy
59
FromCodetoAbstractSpecifica'on
PLresearchershavedevelopedtheirownstandardnota'onforwri'ngdownhowprogramsexecute
– ithasamathema'cal“feel”thatmakesPLresearchersfeelspecialandgivesusgoosebumpsinside
– itoperatesoverabstractexpressionsyntaxlike“e1+e2”– itisusefultoknowthisnota'onifyouwanttoreadspecifica'onsofprogramminglanguageseman'cs• e.g.:StandardML(ofwhichOCamlisadescendent)hasaformaldefini'ongiveninthisnota'on(andC,andJava;butnotOCaml…)
• e.g.:mostpapersintheconferencePOPL(ACMPrinciplesofProg.Lang.)
60
Goal
Ourgoalistoexplainhowanexpressioneevaluatestoavaluev.Inotherwords,wewanttodefineamathema'calrela6onbetweenpairsofexpressionsandvalues.
61
FormalInferenceRulesWedefinethe“evaluatesto”rela'onusingasetof(induc've)rulesthatallowustoprovethatapar'cular(expression,value)pairispartoftherela'on.Arulelookslikethis:
Youreadarulelikethis:
– “ifpremise1canbeprovenandpremise2canbeprovenand...andpremisencanbeproventhenconclusioncanbeproven”
Someruleshavenopremises– thismeanstheirconclusionsarealwaystrue– wecallsuchrules“axioms”or“basecases”
premise1premise2...premise3conclusion
62
Anexamplerule
e1-->v1e2-->v2eval_op(v1,op,v2)==v’e1ope2-->v’
let rec eval (e:exp) : exp = match e with | Op_e(e1,op,e2) -> let v1 = eval e1 in let v2 = eval e2 in
let v’ = eval_op v1 op v2 in v’
“Ife1evaluatestov1ande2evaluatestov2andeval_op(v1,op,v2)isequaltov’thene1ope2evaluatestov’
Asarule:
InEnglish:
Incode:
63
Anexamplerule
iϵΖi-->i
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i ...
“Iftheexpressionisanintegervalue,itevaluatestoitself.”
Asarule:
InEnglish:
Incode:
assertsiisaninteger
64
Anexampleruleconcerningevalua'on
e1-->v1e2[v1/x]-->v2letx=e1ine2-->v2
let rec eval (e:exp) : exp = match e with | Let_e(x,e1,e2) -> let v1 = eval e1 in
eval (substitute v1 x e2) ...
“Ife1evaluatestov1(whichisavalue)ande2withv1subs'tutedforxevaluatestov2thenletx=e1ine2evaluatestov2.”
Asarule:
InEnglish:
Incode:
65
Anexampleruleconcerningevalua'on
λx.e-->λx.e
let rec eval (e:exp) : exp = match e with ... | Fun_e (x,e) -> Fun_e (x,e) ...
“Afunc'onvalueevaluatestoitself.”
Asarule:
InEnglish:
Incode:
typical“lambda”nota'onforafunc'onwithargumentx,bodye
66
Anexampleruleconcerningevalua'on
e1-->λx.ee2-->v2e[v2/x]-->ve1e2-->v
let rec eval (e:exp) : exp = match e with ..| FunCall_e (e1,e2) ->
(match eval e1 with | Fun_e (x,e) -> eval (substitute (eval e2) x e) | ...)
...
“ife1evaluatestoafunc'onwithargumentxandbodyeande2evaluatestoavaluev2andewithv2subs'tutedforxevaluatestovthene1appliedtoe2evaluatestov”
Asarule:
InEnglish:
Incode:
67
Anexampleruleconcerningevalua'on
e1-->recfx=ee2-->ve[recfx=e/f][v/x]-->v2e1e2-->v2
let rec eval (e:exp) : exp = match e with ... | (Rec_e (f,x,e)) as f_val ->
let v = eval e2 in substitute f_val (substitute v x e) g
“uggh”
Asarule:
InEnglish:
Incode:
68
Comparison:Codevs.Rules
Almostisomorphic:– oneruleperpaWern-matchingclause– recursivecalltoevalwheneverthereisa-->premiseinarule– what’sthemaindifference?
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i
| Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x)
| Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1 | Fun_e (x,e) -> eval (Let_e (x,e2,e))
| _ -> raise TypeError) | LetRec_e (x,e1,e2) ->
• (Rec_e (f,x,e)) as f_val ->
let v = eval e2 in substitute f_val f (substitute v x e) e1-->recfx=ee2-->v2e[recfx=e/f][v2/x]-->v3
e1e2-->v3
e1-->v1e2-->v2eval_op(v1,op,v2)==ve1ope2-->v
iϵΖi-->i
e1-->v1e2[v1/x]-->v2letx=e1ine2-->v2
λx.e-->λx.e
e1-->λx.ee2-->v2e[v2/x]-->ve1e2-->v
completeevalcode: completesetofrules:
69
Comparison:Codevs.Rules
• There’snoformalruleforhandlingfreevariables• Noruleforevalua'ngfunc'oncallswhenanon-func'oninthecallerposi'on• Ingeneral,norulewhenfurtherevalua6onisimpossible
– therulesexpressthelegalevalua6onsandsaynothingaboutwhattodoinerrorsitua'ons– thecodehandlestheerrorsitua'onsbyraisingexcep'ons– typetheoristsprovethatwell-typedprogramsdon’trunintoundefinedcases
e1-->v1e2-->v2eval_op(v1,op,v2)==ve1ope2-->v
iϵΖi-->i
e1-->v1e2[v1/x]-->v2letx=e1ine2-->v2
λx.e-->λx.e
e1-->λx.ee2-->v2e[v2/x]-->ve1e2-->v
completeevalcode: completesetofrules:
e1-->recfx=ee2-->v2e[recfx=e/f][v2/x]-->v3e1e2-->v3
let rec eval (e:exp) : exp = match e with | Int_e i -> Int_e i
| Op_e(e1,op,e2) -> eval_op (eval e1) op (eval e2) | Let_e(x,e1,e2) -> eval (substitute (eval e1) x e2) | Var_e x -> raise (UnboundVariable x)
| Fun_e (x,e) -> Fun_e (x,e) | FunCall_e (e1,e2) -> (match eval e1 | Fun_e (x,e) -> eval (Let_e (x,e2,e))
| _ -> raise TypeError) | LetRec_e (x,e1,e2) ->
• (Rec_e (f,x,e)) as f_val ->
let v = eval e2 in substitute f_val f (substitute v x e)
70
Summary 71
• WecanreasonaboutOCamlprogramsusingasubs6tu6onmodel.– integers,bools,strings,chars,andfunc6onsarevalues– valuerule:valuesevaluatetothemselves– letrule:“letx=e1ine2”:subs'tutee1’svalueforxintoe2– funcallrule:“(funx->e2)e1”:subs'tutee1’svalueforxintoe2– reccallrule:“(recx=e1)e2”:likefuncallrule,butalsosubs'tute
recursivefunc'onfornameoffunc'on• Tounwind:subs'tute(recx=e1)forxine1
• Wecanmaketheevalua'onmodelprecisebybuildinganinterpreterandusingthatinterpreterasaspecifica'onofthelanguageseman'cs.
• Wecanalsospecifytheevalua'onmodelusingasetofinferencerules– moreonthisinCOS510
SomeFinalWords 72
• Thesubs'tu'onmodelisonlyamodel.– itdoesnotaccuratelymodelallofOCaml’sfeatures
• I/O,excep'ons,muta'on,concurrency,…• wecanbuildmodelsofthesethings,buttheyaren’tassimple.• evensubs'tu'onistrickytoformalize!
• It’susefulforreasoningabouthigher-orderfunc'ons,correctnessofalgorithms,andop'miza'ons.– wecanuseittoformallyprovethat,forinstance:
• mapf(mapgxs)==map(compfg)xs• proof:byinduc'ononthelengthofthelistxs,usingthedefini'onsofthesubs'tu'onmodel.
– weoienmodelcomplicatedsystems(e.g.,protocols)usingasmallfunc'onallanguageandsubs'tu'on-basedevalua'on.
• Itisnotusefulforreasoningaboutexecu'on'meorspace– morecomplexmodelsneededthere
SomeFinalWords 73
• Thesubs'tu'onmodelisonlyamodel.– itdoesnotaccuratelymodelallofOCaml’sfeatures
• I/O,excep'ons,muta'on,concurrency,…• wecanbuildmodelsofthesethings,buttheyaren’tassimple.• evensubs'tu'onwastrickytoformalize!
• It’susefulforreasoningabouthigher-orderfunc'ons,correctnessofalgorithms,andop'miza'ons.– wecanuseittoformallyprovethat,forinstance:
• mapf(mapgxs)==map(compfg)xs• proof:byinduc'ononthelengthofthelistxs,usingthedefini'onsofthesubs'tu'onmodel.
– weoienmodelcomplicatedsystems(e.g.,protocols)usingasmallfunc'onallanguageandsubs'tu'on-basedevalua'on.
• Itisnotusefulforreasoningaboutexecu'on'meorspace– morecomplexmodelsneededthere
AlonzoChurch,1903-1995
PrincetonProfessor,1929-1967
Youcansaythatagain!Igotitwrongthefirst'meItried,in1932.Fixedthebugby1934,
though.
Church'smistake 74
funxs->map(+)xs
funys->letmapxs=0::xsinf(mapys)
subs'tute:
forfin:
andifyoudon'twatchout,youwillget:
funys->letmapxs=0::xsin(funxs->map(+)xs)(mapys)
Church'smistake 75
funxs->map(+)xs
funys->letmapxs=0::xsinf(mapys)
subs'tute:
forfin:
andifyoudon'twatchout,youwillget:
funys->letmapxs=0::xsin(funxs->map(+)xs)(mapys)
theproblemwasthatthevalueyousubs'tutedin
hadafreevariable(map)initthatwascaptured.
Church'smistake 76
funxs->map(+)xs
funys->letmapxs=0::xsinf(mapys)
subs'tute:
forfin:
todoitright,youneedtorenamesomevariables:
funys->letzxs=0::xsin(funxs->map(+)xs)(zys)
NOWWEAREREALLYDONE!
77