An OCaml definion of OCaml evaluaon, or, Implemen’ng OCaml in OCaml (Part II) · 2017. 10....

Preview:

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