Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
Implemen'ngOCamlinOCaml(PartII)
AnOCamldefini'onofOCamlevalua'on,or,
COS326DavidWalker
PrincetonUniversity
slidescopyright2017DavidWalkerpermissiongrantedtoreusetheseslidesfornon-commercialeduca'onalpurposes
1
LastTimeImplemen'nganinterpreter:Components:• Evaluatorforprimi'veopera'ons• Subs'tu'on• Recursiveevalua'onfunc'onforexpressions
2
ProgramText AST
ASTResult
PrintedResult
parse eval print
typecheck
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)
OurInterpreter 3
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)
OurInterpreter 4
let rec substitute (v:exp) (x:variable) (e:exp) : exp = match e with | Int_e _ -> e | Op_e(e1,op,e2) ->
Op_e(substitute v x e1,op,substitute v x e2) | Var_e y -> if x = y then v else e | Let_e (y,e1,e2) -> Let_e (y, substitute v x e1, if x = y then e2 else substitute v x e2)
let z = 2 inlet z = 3 + z inz
OurInterpreter 5
eval (let x = e1 in e2) ->eval {substitute (eval e1) x e2}
Exampletointerpret: Howtointerpretaletexpression:
substitute v x (let y = e1 in e2) == let y = substitute v x e1 in (if x = y then e2 else substitute v x e2)
Howtosubs'tutevforxintoaletexpression
let z = 2 inlet z = 3 + z inz
OurInterpreter 6
eval (let x = e1 in e2) ->eval {substitute (eval e1) x e2}
eval { substitute (eval 2) z (let z = 3 + z in z) }==
Exampletointerpret: Howtointerpretaletexpression:
substitute v x (let y = e1 in e2) == let y = substitute v x e1 in (if x = y then e2 else substitute v x e2)
Howtosubs'tutevforxintoaletexpression
let z = 2 inlet z = 3 + z inz
OurInterpreter 7
eval { substitute 2 z (let z = 3 + z in z) }==
eval (let x = e1 in e2) ->eval {substitute (eval e1) x e2}
eval { substitute (eval 2) z (let z = 3 + z in z) }==
Exampletointerpret: Howtointerpretaletexpression:
substitute v x (let y = e1 in e2) == let y = substitute v x e1 in (if x = y then e2 else substitute v x e2)
Howtosubs'tutevforxintoaletexpression
let z = 2 inlet z = 3 + z inz
OurInterpreter 8
eval { substitute 2 z (let z = 3 + z in z) }
eval { (let z = (substitute 2 z (3 + z)) in z) }
==
==
eval (let x = e1 in e2) ->eval {substitute (eval e1) x e2}
eval { substitute (eval 2) z (let z = 3 + z in z) }==
Exampletointerpret: Howtointerpretaletexpression:
substitute v x (let y = e1 in e2) == let y = substitute v x e1 in (if x = y then e2 else substitute v x e2)
Howtosubs'tutevforxintoaletexpression
let z = 2 inlet z = 3 + z inz
OurInterpreter 9
eval { substitute 2 z (let z = 3 + z in z) }
eval { (let z = (substitute 2 z (3 + z)) in z) }
==
==
eval (let x = e1 in e2) ->eval {substitute (eval e1) x e2}
eval { substitute (eval 2) z (let z = 3 + z in z) }==
Exampletointerpret: Howtointerpretaletexpression:
substitute v x (let y = e1 in e2) == let y = substitute v x e1 in (if x = y then e2 else substitute v x e2)
Howtosubs'tutevforxintoaletexpression
no'cewedon'tsubs'tute2inzhere
let z = 2 inlet z = 3 + z inz
OurInterpreter 10
eval { substitute 2 z (let z = 3 + z in z) }
eval { (let z = (substitute 2 z (3 + z)) in z) }
==
==
eval { let z = 3 + 2 in z }==
eval (let x = e1 in e2) ->eval {substitute (eval e1) x e2}
eval { substitute (eval 2) z (let z = 3 + z in z) }==
Exampletointerpret: Howtointerpretaletexpression:
substitute v x (let y = e1 in e2) == let y = substitute v x e1 in (if x = y then e2 else substitute v x e2)
Howtosubs'tutevforxintoaletexpression
SCALINGUPTHELANGUAGE(MOREFEATURES,MOREFUN)
11
ScalinguptheLanguage 12type 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 13type 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 14type 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 15type 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 16type 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 17
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 18
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 19
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 20
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)
e1hadbeferevaluatetoafunc'onvalue,elsewehaveatypeerror.
ScalinguptheLanguage 21
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.
Simplifyingalifle 22
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) -> eval (substitute (eval e2) x e) | _ -> raise TypeError)
Wedon’treallyneedtopafern-matchone2.
Justevaluatehere
Simplifyingalifle 23
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 24
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: 25
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:“Letissyntac'csugarforafunc'oncall”Syntac'csugar:Anewfeaturedefinedbyasimple,localtransforma'on.
Recursivedefini'ons 26type 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 27type 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 28type 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)
AbeferIRwouldjustdeleteFun_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:
29
Evalua'ngRecursiveFunc'ons 30
Basicevalua'onruleforrecursivefunc'ons:
(recfx=body)arg-->body[arg/x][recfx=body/f]
en'refunc'onsubs'tutedforfunc'onname
argumentvaluesubs'tutedforparameter
Evalua'ngRecursiveFunc'ons 31
let g = rec f x -> if x
Evalua'ngRecursiveFunc'ons
32
RecursiveFunc'onCall:
TheSubs'tu'on:
TheResult:
(if x if x if x
Evalua'ngRecursiveFunc'ons 33
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 eval (substitute v x e)
| (Rec_e (f,x,e)) as f_val -> let v = eval e2 in eval (substitute f_val f (substitute v x e))
| _ -> raise TypeError)
pa-ernasxmatchthepafernandbindsxtovalue
MoreEvalua'on 34(rec fact n = if n 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 3 * (2 * (rec fact n = ...)(2-1))-->3 * (2 * (rec fact n = ...)(1))-->3 * 2 * (if 1 3 * 2 * 1
AMATHEMATICALDEFINITION*OFOCAMLEVALUATION
*it’sapar'aldefini'onandthisisabigtopic;formore,seeCOS510
35
FromCodetoAbstractSpecifica'on
OCamlcodecangivealanguageseman'cs– advantage:itcanbeexecuted,sowecantryitout– advantage:itisamazinglyconcise
• especiallycomparedtowhatyouwouldhavewrifeninJava– disadvantage:itisalifleuglytooperateoverconcreteMLdatatypeslike“Op_e(e1,Plus,e2)”asopposedto“e1+e2”
36
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.)
37
Goal
Ourgoalistoexplainhowanexpressioneevaluatestoavaluev.Inotherwords,wewanttodefineamathema'calrela'onbetweenpairsofexpressionsandvalues.
38
FormalInferenceRulesWedefinethe“evaluatesto”rela'onusingasetof(induc've)rulesthatallowustoprovethatapar'cular(expression,value)pairispartoftherela'on.Arulelookslikethis:
Youreadarulelikethis:
– “ifpremise1canbeprovenandpremise2canbeprovenand...andpremisencanbeproventhenconclusioncanbeproven”
Someruleshavenopremises– thismeanstheirconclusionsarealwaystrue– wecallsuchrules“axioms”or“basecases”
premise1premise2...premise3conclusion
39
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:
40
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
41
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:
42
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
43
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:
44
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:
45
Comparison:Codevs.Rules
Almostisomorphic:– oneruleperpafern-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:
46
Comparison:Codevs.Rules
• There’snoformalruleforhandlingfreevariables• Noruleforevalua'ngfunc'oncallswhenanon-func'oninthecallerposi'on• Ingeneral,norulewhenfurtherevalua'onisimpossible
– therulesexpressthelegalevalua'onsandsaynothingaboutwhattodoinerrorsitua'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)
47
Summary 48
• WecanreasonaboutOCamlprogramsusingasubs'tu'onmodel.– integers,bools,strings,chars,andfunc'onsarevalues– 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 49
• 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.
– weozenmodelcomplicatedsystems(e.g.,protocols)usingasmallfunc'onallanguageandsubs'tu'on-basedevalua'on.
• Itisnotusefulforreasoningaboutexecu'on'meorspace– morecomplexmodelsneededthere
SomeFinalWords 50
• 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.
– weozenmodelcomplicatedsystems(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 51
funxs->map(+)xs
funys->letmapxs=0::xsinf(mapys)
subs'tute:
forfin:
andifyoudon'twatchout,youwillget:
funys->letmapxs=0::xsin(funxs->map(+)xs)(mapys)
Church'smistake 52
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 53
funxs->map(+)xs
funys->letmapxs=0::xsinf(mapys)
subs'tute:
forfin:
todoitright,yourename(alpha-convert)somevariables:
funys->letzxs=0::xsin(funxs->map(+)xs)(zys)
ASSIGNMENT#4
54
TwoPartsPart1:Buildyourowninterpreter
– Morefeatures:booleans,pairs,lists,match– Differentmodel:environment-basedvssubs'tu'on-based
• TheabstractsyntaxtreeFun_e(_,_)isnolongeravalue– aFun_eisnotaresultofacomputa'on
• Thereisonemorecomputa'onsteptodo:– crea'onofaclosurefromaFun_eexpression
Part2:Provefactsaboutprogramsusingequa'onalreasoning– wealreadysawabitofequa'onalreasoningtoday:
• ife1-->e2thene1==e2– morenextweek
55
FUNCTIONCLOSURES
56
ClosuresConsiderthefollowingprogram:
let choose (arg:bool * int * int) : int -> int = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
57
ClosuresConsiderthefollowingprogram:
Itsexecu'onbehavioraccordingtothesubs'tu'onmodel:
let choose (arg:bool * int * int) : int -> int = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
choose (true, 1, 2)
58
ClosuresConsiderthefollowingprogram:
Itsexecu'onbehavioraccordingtothesubs'tu'onmodel:
let choose (arg:bool * int * int) : int -> int = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
choose (true, 1, 2) --> let (b, x, y) = (true, 1, 2) in if b then (fun n -> n + x) else (fun n -> n + y)
59
ClosuresConsiderthefollowingprogram:
Itsexecu'onbehavioraccordingtothesubs'tu'onmodel:
let choose (arg:bool * int * int) : int -> int = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
choose (true, 1, 2) --> let (b, x, y) = (true, 1, 2) in if b then (fun n -> n + x) else (fun n -> n + y) --> if true then (fun n -> n + 1) else (fun n -> n + 2)
60
ClosuresConsiderthefollowingprogram:
Itsexecu'onbehavioraccordingtothesubs'tu'onmodel:
let choose (arg:bool * int * int) : int -> int = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
choose (true, 1, 2) --> let (b, x, y) = (true, 1, 2) in if b then (fun n -> n + x) else (fun n -> n + y) --> if true then (fun n -> n + 1) else (fun n -> n + 2) --> (fun n -> n + 1)
61
Subs'tu'onandCompiledCodelet choose arg = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
62
Subs'tu'onandCompiledCodechoose: mov rb r_arg[0] mov rx r_arg[4] mov ry r_arg[8] compare rb 0 ... jmp ret main: ... jmp choose
let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
compile
63
Subs'tu'onandCompiledCode
let (b, x, y) = (true, 1, 2) in if b then (fun n -> n + x) else (fun n -> n + y)
choose: mov rb r_arg[0] mov rx r_arg[4] mov ry r_arg[8] compare rb 0 ... jmp ret main: ... jmp choose
let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
compile
executewithsubs'tu'on
64
Subs'tu'onandCompiledCode
let (b, x, y) = (true, 1, 2) in if b then (fun n -> n + x) else (fun n -> n + y)
choose: mov rb r_arg[0] mov rx r_arg[4] mov ry r_arg[8] compare rb 0 ... jmp ret main: ... jmp choose
let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
compile
executewithsubs'tu'on
executewithsubs'tu'on==generatenewcodeblockwithparametersreplacedbyarguments
65
choose: mov rb r_arg[0] mov rx r_arg[4] mov ry r_arg[8] ... jmp ret main: ... jmp choose
Subs'tu'onandCompiledCode
let (b, x, y) = (true, 1, 2) in if b then (fun n -> n + x) else (fun n -> n + y)
choose: mov rb r_arg[0] mov rx r_arg[4] mov ry r_arg[8] compare rb 0 ... jmp ret main: ... jmp choose
let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
compile
executewithsubs'tu'on
executewithsubs'tu'on==generatenewcodeblockwithparametersreplacedbyarguments
choose_subst: mov rb 0xF8[0] mov rx 0xF8[4] mov ry 0xF8[8] compare rb 0 ... jmp ret
0xF8: 0 1 2
66
choose: mov rb r_arg[0] mov rx r_arg[4] mov ry r_arg[8] ... jmp ret main: ... jmp choose
Subs'tu'onandCompiledCode
let (b, x, y) = (true, 1, 2) in if b then (fun n -> n + x) else (fun n -> n + y)
choose: mov rb r_arg[0] mov rx r_arg[4] mov ry r_arg[8] compare rb 0 ... jmp ret main: ... jmp choose
let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y) choose (true, 1, 2)
compile
executewithsubs'tu'on
executewithsubs'tu'on==generatenewcodeblockwithparametersreplacedbyarguments
choose_subst: mov rb 0xF8[0] mov rx 0xFF44] mov ry 0xFF84[8] compare rb 0 ... jmp ret
if true then (fun n -> n + 1) else (fun n -> n + 2)
executewithsubs'tu'on 0xF8: 0 1
2 choose_subst2: compare 1 0 ... jmp ret
67
Whatwearen’tgoingtodo• Thesubs'tu'onmodelofevalua'onisjustamodel.Itsays
thatwegeneratenewcodeateachstepofacomputa'on.Wedon’tdothatinreality.Tooexpensive!
• Thesubs'tu'onmodelisafaithfulmodelforreasoningabouttherela'onshipbetweeninputsandoutputsofafunc'onbutitdoesn’ttellusmuchabouttheresourcesthatareusedalongtheway.
• I’mgoingtotellyoualiflebitabouthowMLprogramsarecompiledsoyoucanunderstandhowmuchspaceyourprogramswilluse.Understandingthespaceconsump'onofyourprogramsisanimportantcomponentinmakingtheseprogramsmoreefficient.
68
Compilingfunc'ons
let add (x:int*int) : int = let (y,z) = x in y + z
# argument in r1 # return address in r0 add: ld r2, r1[0] # y in r2 ld r3, r1[4] # z in r3 add r4, r2, r3 # sum in r4 jmp r0
Generaltac'c:ReducetheproblemofcompilingML-likefunc'onstotheproblemofcompilingC-likefunc'ons.Somefunc'onsarealreadyC-like:
69
Butwhataboutnested,higher-orderfunc'ons?
let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y)
let choose arg = let (b, x, y) = arg in if b then f1 else f2
let f1 n = n + x
let f2 n = n + y
?
?
?
70
Butwhataboutnested,higher-orderfunc'ons?
let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x) else (fun n -> n + y)
let choose arg = let (b, x, y) = arg in if b then f1 else f2
let f1 n = n + x
let f2 n = n + y
?
?
?
Darn!Doesn’tworknaively.Nestedfunc'onscontainfreevariables.Simpleunnes'ngleavesthemundefined.
71
Butwhataboutnested,higher-orderfunc'ons?• Wecan’texecuteafunc'onlikethefollowing:
• Butwecanexecuteaclosurewhichisapairofsomecodeandanenvironment:
let f2 n = n + y
let f2 (n,env) = n + env.y
{y = 1}
environmentcode
closure
72
ClosureConversionClosureconversion(alsocalledlambdalizing)convertsopen,nestedfunc'onsintoclosed,top-levelfunc'ons.let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x + y) else (fun n -> n + y)
73
ClosureConversionClosureconversion(alsocalledlambdalizing)convertsopen,nestedfunc'onsintoclosed,top-levelfunc'ons.let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x + y) else (fun n -> n + y)
let choose (arg,env) = let (b, x, y) = arg in if b then (f1, {xe=x; ye=y}) else (f2, {ye=y}) let f1 (n,env) = n + env.xe + env.ye
let f2 (n,env) = n + env.ye
createclosures
useenvironmentvariablesinsteadoffreevariables
addenvironmentparameter
74
ClosureConversionClosureconversionconvertsopen,nestedfunc'onsintoclosed,top-levelfunc'ons.let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x + y) else (fun n -> n + y)
let choose (arg,env) = let (b, x, y) = arg in if b then (f1, {xe=x; ye=y}) else (f2, {ye=y}) let f1 (n,env) = n + env.xe + env.ye
let f2 (n,env) = n + env.ye
(choose (true,1,2)) 3
createclosures
useenvironmentvariablesinsteadoffreevariables
addenvironmentparameter
let c_closure = (choose, ()) in (* create closure *) let (c_code, c_cenv) = c_closure in (* extract code, env *) let f_closure = c_code ((true,1,2), c_env) in (* call choose code, extract f code, env *) let (f_code, f_env) = f_closure in (* extract code, env *) f_code (3, f_env) (* call f code *) ;;
75
ClosureConversionClosureconversionconvertsopen,nestedfunc'onsintoclosed,top-levelfunc'ons.let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x + y) else (fun n -> n + y)
let choose (arg,env) = let (b, x, y) = arg in if b then (f1, {xe=x; ye=y}) else (f2, {ye=y}) let f1 (n,env) = n + env.xe + env.ye
let f2 (n,env) = n + env.ye
(choose (true,1,2)) 3
createclosures
useenvironmentvariablesinsteadoffreevariables
addenvironmentparameter
let c_closure = (choose, ()) in (* create closure *) let (c_code, c_cenv) = c_closure in (* extract code, env *) let f_closure = c_code ((true,1,2), c_env) in (* call choose code, extract f code, env *) let (f_code, f_env) = f_closure in (* extract code, env *) f_code (3, f_env) (* call f code *)
76
ClosureConversionClosureconversionconvertsopen,nestedfunc'onsintoclosed,top-levelfunc'ons.let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x + y) else (fun n -> n + y)
let choose (arg,env) = let (b, x, y) = arg in if b then (f1, {xe=x; ye=y}) else (f2, {ye=y}) let f1 (n,env) = n + env.xe + env.ye
let f2 (n,env) = n + env.ye
(choose (true,1,2)) 3
createclosures
useenvironmentvariablesinsteadoffreevariables
addenvironmentparameter
let c_closure = (choose, ()) in (* create closure *) let (c_code, c_cenv) = c_closure in (* extract code, env *) let f_closure = c_code ((true,1,2), c_env) in (* call choose code, extract f code, env *) let (f_code, f_env) = f_closure in (* extract code, env *) f_code (3, f_env) (* call f code *)
77
ClosureConversionClosureconversionconvertsopen,nestedfunc'onsintoclosed,top-levelfunc'ons.let choose arg = let (b, x, y) = arg in if b then (fun n -> n + x + y) else (fun n -> n + y)
let choose (arg,env) = let (b, x, y) = arg in if b then (f1, {xe=x; ye=y}) else (f2, {ye=y}) let f1 (n,env) = n + env.xe + env.ye
let f2 (n,env) = n + env.ye
(choose (true,1,2)) 3
createclosures
useenvironmentvariablesinsteadoffreevariables
addenvironmentparameter
let c_closure = (choose, ()) in (* create closure *) let (c_code, c_cenv) = c_closure in (* extract code, env *) let f_closure = c_code ((true,1,2), c_env) in (* call choose code, extract f code, env *) let (f_code, f_env) = f_closure in (* extract code, env *) f_code (3, f_env) (* call f code *)
78
Summary:Assignment#4• Inenvironment-basedevaluator,valuesaredrawnfroman
environment• Inordertoimplement,nested,higher-orderfunc'ons,one
needstoperformclosureconversion,whichistheprocessofimplemen'ngfunc'onsusingadatastructure:apairofcodeplusanenvironmentthatgivesvaluestothe(previously)freevariablesinthecode(makingthatcode"closed")
• Youhavetwoweeksforassignment#4– Why?becauselastyearstudentfoundunderstandingandwri'ngtheevaluatorprefytough!
– Don'twaitun'lnextweektostart!– Putinafullweek'sworthofworkthisweek
79