Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env...
Transcript of Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env...
![Page 1: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/1.jpg)
CMPS 112: Spring 2019
Comparative Programming Languages
Owen Arden
UC Santa Cruz
Environments and closures
Based on course materials developed by Nadia Polikarpova
RoadmapPast three weeks:
• How do we use a functional language?
Next three weeks:
• How do we implement a functional language? • … in a functional language (of course)
This week: Interpreter
• How do we evaluate a program given its abstract syntax tree (AST)? • How do we prove properties about our interpreter (e.g. that certain programs
never crash)?
!2
The Nano LanguageFeatures of Nano:
1. Arithmetic expressions
2. Variables and let-bindings
3. Functions 4. Recursion
!3
![Page 2: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/2.jpg)
Reminder: CalculatorArithmetic expressions:
e::=n|e1+e2|e1-e2|e1*e2
Example:
4+13==>17
!4
Reminder: CalculatorHaskell datatype to represent arithmetic expressions:
dataExpr=NumInt|AddExprExpr|SubExprExpr|MulExprExpr
Haskell function to evaluate an expression:
eval::Expr->Inteval(Numn)=n
eval(Adde1e2)=evale1+evale2eval(Sube1e2)=evale1-evale2eval(Mule1e2)=evale1*evale2
!5
Reminder: CalculatorAlternative representation:
dataBinop=Add|Sub|Mul
dataExpr=NumInt--number|BinBinopExprExpr--binaryexpression
Evaluator for alternative representation:
eval::Expr->Inteval(Numn)=neval(BinAdde1e2)=evale1+evale2eval(BinSube1e2)=evale1-evale2eval(BinMule1e2)=evale1*evale2
!6
![Page 3: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/3.jpg)
The Nano LanguageFeatures of Nano:
1. Arithmetic expressions [done] 2. Variables and let-bindings
3. Functions 4. Recursion
!7
Extension: variablesLet’s add variables and let bindings!
e::=n|x|e1+e2|e1-e2|e1*e2|letx=e1ine2
Example:
letx=4+13in--17
lety=7-5in--2x*y
==>34
!8
Extension: variablesHaskell representation:
dataExpr=NumInt--number|???--variable|BinBinopExprExpr--binaryexpression|???--letexpression
!9
![Page 4: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/4.jpg)
Extension: variablestypeId=String
dataExpr=NumInt--number|VarId--variable|BinBinopExprExpr--binaryexpression|LetIdExprExpr--letexpression
Haskell function to evaluate an expression:
eval::Expr->Inteval(Numn)=neval(Varx)=???...
!10
Extension: variablestypeId=String
dataExpr=NumInt--number|VarId--variable|BinBinopExprExpr--binaryexpression|LetIdExprExpr--letexpression
Haskell function to evaluate an expression:
eval::Expr->Inteval(Numn)=neval(Varx)=???...
!11
How do we evaluate a variable?
We have to remember which value it was bound to!
EnvironmentAn expression is evaluated in an environment, which maps all its free variables to values
Examples:
x*y=[x:17,y:2]=>34
x*y=[x:17]=>Error:unboundvariabley
x*(lety=2iny)=[x:17]=>34
!12
• How should we represent the environment?
• Which operations does it support?
![Page 5: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/5.jpg)
Extension: variables
!13
http://tiny.cc/cmps112-vars-ind
Extension: variables
!14
http://tiny.cc/cmps112-vars-grp
Environment: APITo evaluate letx=e1ine2 in env:
• evaluate e2 in an extended environment env+[x:v] • where v is the result of evaluating e1
To evaluate x in env: • lookup the most recently added binding for x
typeValue=Int
dataEnv=...--representationnotthatimportant
--|Addanewbindingadd::Id->Value->Env->Env
--|Lookupthemostrecentlyaddedbindinglookup::Id->Env->Value
!15
![Page 6: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/6.jpg)
Evaluating expressionsBack to our expressions… now with environments!
dataExpr=NumInt--number|VarId--variable|BinBinopExprExpr--binaryexpression|LetIdExprExpr--letexpression
!16
Evaluating expressionsHaskell function to evaluate an expression:
eval::Env->Expr->Valueevalenv(Numn)=nevalenv(Varx)=lookupxenvevalenv(Binope1e2)=fv1v2wherev1=evalenve1v2=evalenve2f=caseopofAdd->(+)Sub->(-)Mul->(*)evalenv(Letxe1e2)=evalenv'e2wherev=evalenve1env'=addxvenv
!17
Example evaluationNano expression
letx=1inlety=(letx=2inx)+xinletx=3inx+y
is represented in Haskell as:
exp1=Let"x"(Num1)(Let"y"(Add(Let"x"(Num2)(Varx))(Varx))(Let"x"(Num3)(Add(Varx)(Vary))))
!18
exp3
exp2
exp4
exp5
![Page 7: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/7.jpg)
Example evaluationeval[]exp1=>eval[](Let"x"(Num1)exp2)=>eval[("x",eval[](Num1))]exp2=>eval[("x",1)](Let"y"(Addexp3exp4)exp5)=>eval[("y",(eval[("x",1)](Addexp3exp4))),("x",1)]exp5=>eval[("y",(eval[("x",1)](Let"x"(Num2)(Var"x"))+eval[("x",1)](Var"x"))),("x",1)]exp5=>eval[("y",(eval[("x",2),("x",1)](Var"x")--newbindingforx+1)),("x",1)]exp5=>eval[("y",(2--uselatestbindingforx+1)),("x",1)]exp5=>eval[("y",3),("x",1)](Let"x"(Num3)(Add(Var"x")(Var"y")))
!19
Example evaluation=>eval[("y",3),("x",1)](Let"x"(Num3)(Add(Var"x")(Var“y")))=>eval[("x",3),("y",3),("x",1)]--newbindingforx(Add(Var"x")(Var"y"))=>eval[("x",3),("y",3),("x",1)](Var"x")+eval[("x",3),("y",3),("x",1)](Var"y")=>3+3=>6
!20
Example evaluationSame evaluation in a simplified format (Haskell Expr terms replaced by their “pretty-printed version”):
eval[]{letx=1inlety=(letx=2inx)+xinletx=3inx+y}=>eval[x:(eval[]1)]{lety=(letx=2inx)+xinletx=3inx+y}=>eval[x:1]{lety=(letx=2inx)+xinletx=3inx+y}=>eval[y:(eval[x:1]{(letx=2inx)+x}),x:1]{letx=3inx+y}=>eval[y:(eval[x:1]{letx=2inx}+eval[x:1]{x}),x:1]{letx=3inx+y}--newbindingforx:=>eval[y:(eval[x:2,x:1]{x}+eval[x:1]{x}),x:1]{letx=3inx+y}--uselatestbindingforx:=>eval[y:(2+eval[x:1]{x}),x:1]{letx=3inx+y}=>eval[y:(2+1),x:1]{letx=3inx+y} !21
![Page 8: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/8.jpg)
Example evaluation=>eval[y:(2+1),x:1]{letx=3inx+y}=>eval[y:3,x:1]{letx=3inx+y}--newbindingforx:=>eval[x:3,y:3,x:1]{x+y}=>eval[x:3,y:3,x:1]x+eval[x:3,y:3,x:1]y--uselatestbindingforx:=>3+3=>6
!22
Runtime errorsHaskell function to evaluate an expression:
eval::Env->Expr->Valueevalenv(Numn)=nevalenv(Varx)=lookupxenv--canfail!evalenv(Binope1e2)=fv1v2wherev1=evalenve1v2=evalenve2f=caseopofAdd->(+)Sub->(-)Mul->(*)evalenv(Letxe1e2)=evalenv'e2wherev=evalenve1env'=addxvenv
How do we make sure lookup doesn’t cause a run-time error?
!23
Free vs bound variablesIn evalenve, env must contain bindings for all free variables of e!
• an occurrence of x is free if it is not bound
• an occurrence of x is bound if it’s inside e2 where letx=e1ine2
• evaluation succeeds when an expression is closed!
!24
![Page 9: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/9.jpg)
QUIZ
!25
http://tiny.cc/cmps112-free-ind
QUIZ
!26
http://tiny.cc/cmps112-free-grp
The Nano LanguageFeatures of Nano:
1. Arithmetic expressions [done] 2. Variables and let-bindings [done] 3. Functions 4. Recursion
!27
![Page 10: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/10.jpg)
Extension: functionsLet’s add lambda abstraction and function application!
e::=n|x|e1+e2|e1-e2|e1*e2|letx=e1ine2|\x->e--abstraction|e1e2--application
Example:
letc=42inletcTimes=\x->c*xincTimes2==>84
!28
Extension: functionsHaskell representation:
dataExpr=NumInt--number|VarId--variable|BinBinopExprExpr--binaryexpression|LetIdExprExpr--letexpression|???--abstraction|???--application
!29
Extension: functionsHaskell representation:
dataExpr=NumInt--number|VarId--variable|BinBinopExprExpr--binaryexpression|LetIdExprExpr--letexpression|LamIdExpr--abstraction|AppExprExpr--application
!30
![Page 11: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/11.jpg)
Extension: functionsExample:
letc=42inletcTimes=\x->c*xincTimes2
represented as:
Let"c"(Num42)(Let"cTimes"(Lam"x"(Mul(Var"c")(Var"x")))(App(Var"cTimes")(Num2)))
!31
Extension: functionsExample:
letc=42inletcTimes=\x->c*xincTimes2
How should we evaluate this expression?
eval[]{letc=42inletcTimes=\x->c*xincTimes2}=>eval[c:42]{letcTimes=\x->c*xincTimes2}=>eval[cTimes:???,c:42]{cTimes2}
What is the value of cTimes???
!32
Rethinking our valuesUntil now: a program evaluates to an integer (or fails)
typeValue=Int
typeEnv=[(Id,Value)]
eval::Env->Expr->Value
!33
![Page 12: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/12.jpg)
Rethinking our valuesWhat do these programs evaluate to?
(1)\x->2*x==>???
(2)letf=\x->\y->2*(x+y)inf5
==>???
Conceptually, (1) evaluates to itself (not exactly, see later). while (2) evaluates to something equivalent to \y->2*(5+y)
!34
Rethinking our valuesNow: a program evaluates to an integer or a lambda abstraction (or fails)
• Remember: functions are first-class values
Let’s change our definition of values!
dataValue=VNumInt|VLam???--Whatinfodoweneedtostore?--OthertypesstaythesametypeEnv=[(Id,Value)]
eval::Env->Expr->Value
!35
Function valuesHow should we represent a function value?
letc=42inletcTimes=\x->c*xincTimes2
We need to store enough information about cTimes so that we can later evaluate any application of cTimes (like cTimes2)!
First attempt:
dataValue=VNumInt
|VLamIdExpr--formal+body
!36
![Page 13: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/13.jpg)
Function valuesLet’s try this!
eval[]{letc=42inletcTimes=\x->c*xincTimes2}=>eval[c:42]{letcTimes=\x->c*xincTimes2}=>eval[cTimes:(\x->c*x),c:42]{cTimes2}--evaluatethefunction:=>eval[cTimes:(\x->c*x),c:42]{(\x->c*x)2}--evaluatetheargument,bindtox,evaluatebody:=>eval[x:2,cTimes:(\x->c*x),c:42]{c*x}=>42*2=>84
Looks good… can you spot a problem?!37
QUIZ
!38
http://tiny.cc/cmps112-cscope-ind
QUIZ
!39
http://tiny.cc/cmps112-cscope-grp
![Page 14: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/14.jpg)
Static vs Dynamic ScopingWhat we want:
letc=42inletcTimes=\x->c*xinletc=5incTimes2=>84
Lexical (or static) scoping:
• each occurrence of a variable refers to the most recent binding in the program text
• definition of each variable is unique and known statically • good for readability and debugging: don’t have to figure out where a variable
got “assigned”
!40
Static vs Dynamic ScopingWhat we don’t want:
letc=42inletcTimes=\x->c*xinletc=5incTimes2=>10
Dynamic scoping:
• each occurrence of a variable refers to the most recent binding during program execution
• can’t tell where a variable is defined just by looking at the function body • nightmare for readability and debugging:
!41
Static vs Dynamic ScopingDynamic scoping:
• each occurrence of a variable refers to the most recent binding during program execution
• can’t tell where a variable is defined just by looking at the function body • nightmare for readability and debugging:
letcTimes=\x->c*xinletc=5inletres1=cTimes2in--==>10
letc=10inletres2=cTimes2in--==>20!!!res2-res1
!42
![Page 15: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/15.jpg)
Function valuesdataValue=VNumInt|VLamIdExpr--formal+body
This representation can only implement dynamic scoping!
letc=42in
letcTimes=\x->c*xin
letc=5in
cTimes2
evaluates as:
eval[]
{letc=42inletcTimes=\x->c*xinletc=5incTimes2}
!43
Function valueseval[]{letc=42inletcTimes=\x->c*xinletc=5incTimes2}=>eval[c:42]{letcTimes=\x->c*xinletc=5incTimes2}=>eval[cTimes:(\x->c*x),c:42]{letc=5incTimes2}=>eval[c:5,cTimes:(\x->c*x),c:42]{cTimes2}=>eval[c:5,cTimes:(\x->c*x),c:42]{(\x->c*x)2}=>eval[x:2,c:5,cTimes:(\x->c*x),c:42]{c*x}--latestbindingforcis5!=>5*2=>10
Lesson learned: need to remember what c was bound to when cTimes was defined!
• i.e. “freeze” the environment at function definition
!44
ClosuresTo implement lexical scoping, we will represent function values as closures
Closure = lambda abstraction (formal + body) + environment at function definition
dataValue=VNumInt|VClosEnvIdExpr--env+formal+body
!45
![Page 16: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/16.jpg)
ClosuresOur example:
eval[]{letc=42inletcTimes=\x->c*xinletc=5incTimes2}=>eval[c:42]{letcTimes=\x->c*xinletc=5incTimes2}--remembercurrentenv:=>eval[cTimes:<[c:42],\x->c*x>,c:42]{letc=5incTimes2}=>eval[c:5,cTimes:<[c:42],\x->c*x>,c:42]{cTimes2}=>eval[c:5,cTimes:<[c:42],\x->c*x>,c:42]{<[c:42],\x->c*x>2}--restoreenvtotheoneinsidetheclosure,thenbind2tox:=>eval[x:2,c:42]{c*x}=>42*2=>84
!46
QUIZ
!47http://tiny.cc/cmps112-env-ind
QUIZ
!48http://tiny.cc/cmps112-env-grp
![Page 17: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/17.jpg)
Free vs bound variables• An occurrence of x is free if it is not bound
• An occurrence of x is bound if it’s inside
◦ e2 where letx=e1ine2
◦ e where \x->e • A closure environment has to save all free variables of a function definition!
leta=20inletf=\x->lety=x+1inletg=\z->y+zina+gx--aistheonlyfreevariable!in...
!49
EvaluatorLet’s modify our evaluator to handle functions!
dataValue=VNumInt|VClosEnvIdExpr--env+formal+bodyeval::Env->Expr->Valueevalenv(Numn)=VNumn--mustwrapinVNumnow!evalenv(Varx)=lookupxenvevalenv(Binope1e2)=VNum(fv1v2)where(VNumv1)=evalenve1(VNumv2)=evalenve2f=...--asbeforeevalenv(Letxe1e2)=evalenv'e2wherev=evalenve1env'=addxvenvevalenv(Lamxbody)=???--constructaclosureevalenv(Appfunarg)=???--evalfun,thenarg,thenapply
!50
EvaluatorEvaluating functions:
• Construct a closure: save environment at function definition • Apply a closure: restore saved environment, add formal, evaluate the body
eval::Env->Expr->Value...evalenv(Lamxbody)=VClosenvxbodyevalenv(Appfunarg)=evalbodyEnvbodywhere(VClosclosEnvxbody)=evalenvfun--evalfunctiontoclosurevArg=evalenvarg--evalargumentbodyEnv=addxvArgclosEnv
!51
![Page 18: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/18.jpg)
EvaluatorEvaluating functions:
• Construct a closure: save environment at function definition • Apply a closure: restore saved environment, add formal, evaluate the body
eval::Env->Expr->Value...evalenv(Lamxbody)=VClosenvxbodyevalenv(Appfunarg)=letvArg=evalenvarg--evalargumentletbodyEnv=addxvArgclosEnvcase(evalenvfun)of--evalfunctiontoclosure(VClosclosEnvxbody)->evalbodyEnvbody_->???
!52
Quiz
!53
http://tiny.cc/cmps112-enveval-ind
Quiz
!54
http://tiny.cc/cmps112-enveval-grp
![Page 19: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/19.jpg)
Evaluatoreval[]
{letf=\x->x+yinlety=10inf5}
=>eval[f:<[],\x->x+y>]
{lety=10inf5}
=>eval[y:10,f:<[],\x->x+y>]
{f5}
=>eval[y:10,f:<[],\x->x+y>]
{<[],\x->x+y>5}
=>eval[x:5]--envgotreplacedbyclosureenv+formal!
{x+y}--yisunbound!
!55
Quiz
!56
http://tiny.cc/cmps112-enveval2-ind
Quiz
!57
http://tiny.cc/cmps112-enveval2-grp
![Page 20: Comparative Programming Languagesowen/courses/cmps112/spr19/slides/env.key.pdfIn eval env e, env must contain bindings for all free variables of e! • an occurrence of x is free if](https://reader033.fdocuments.in/reader033/viewer/2022042204/5ea5d017425cd23e8f12f7f4/html5/thumbnails/20.jpg)
Evaluatoreval[]
{letf=\n->n*f(n-1)inf5}
=>eval[f:<[],\n->n*f(n-1)>]
{f5}
=>eval[f:<[],\n->n*f(n-1)>]
{<[],\n->n*f(n-1)>5}
=>eval[n:5]--envgotreplacedbyclosureenv+formal!
{n*f(n-1)}--fisunbound!
Lesson learned: to support recursion, we need a different way of constructing the closure environment!
!58