79
Implemen’ng OCaml in OCaml (Part II) An OCaml defini’on of OCaml evalua’on, or, COS 326 David Walker Princeton University slides copyright 2017 David Walker permission granted to reuse these slides for non-commercial educa’onal purposes 1

An OCaml definion of OCaml evaluaon, or, Implemen’ng OCaml in OCaml (Part II) · 2017. 10. 4. · (Part II) An OCaml definion of OCaml evaluaon, or, COS 326 ... How to subs’tute

  • 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