+ All Categories
Home > Documents > Implementing functional languages with abstract...

Implementing functional languages with abstract...

Date post: 27-May-2020
Category:
Upload: others
View: 10 times
Download: 1 times
Share this document with a friend
109
Implementing functional languages with abstract machines Hayo Thielecke University of Birmingham http://www.cs.bham.ac.uk/ ~ hxt December 9, 2015
Transcript
Page 1: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Implementing functional languages with abstractmachines

Hayo ThieleckeUniversity of Birmingham

http://www.cs.bham.ac.uk/~hxt

December 9, 2015

Page 2: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Contents

Introduction

Lambda calculus and programming languages

CEK machine

CEK machine and control

Optimizations and lambda calculus

Page 3: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Structure of the module

Parsing X

I Progression from: Language + Logic, Models of Computation

I abstract machines, formal,“mathy”

Compiling C with Clang X

I Progression from: Computer Systems + Architecture, C/C++

I not so formal, by example, x86 machine code

Implementing functional languages

I Progression from: functional programming

I builds on abstract machines and C stack

I the most research-led section, goes beyond Dragon Book

Page 4: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Language design

There are trade-offs in programming language design andimplementation.If you know both C and functional languages, you understandmuch then just knowing one of them.They are at opposite ends of spectrum of language design.

Page 5: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

First-class functions and language design trade-offs

Can a function be:

1. passed as a parameter to another function?

2. returned as the result of another function?

3. defined inside another function and thereby have access to itsvariables?

I In C, you can do 1 and 2, using function pointers, but not 3.

I In Pascal, you can do 1 and 3 but not 2. Needs a “static link”in the stack frame.

I In Gnu C, you can do all 3, but can get undefined behaviourfrom returning functions.

I In functional languages, you can do all 3 without restrictions.More powerful, less efficient, as it needs a garbage collector.

Page 6: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Big ideas in functional language implementation

I Implementing languages like OCaml (or F], or Scheme, orClojure, . . . ) amounts to implementing call-by-value lambdacalculus

I There are many abstract machines for functional languages

I They share some critical ingredients: call stack and closures

I There are similarities to the way C is implemented using stackand frame pointer

Page 7: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Lambda calculus and programming language (pre-)history

I 1879: Frege’s Begriffsschrift clarified variables and functions

I 1930s: Church invents lambda calculus

I Church and Turing invent fixpoint combinators

I Haskell Curry compiles lambda calculus into S and Kcombinators

I Lisp implements lambda, but without closures (dynamicbinding)

I Landin notices that Algol-like languages can be desugared intolambda calculus

I 1964: Landin’s SECD machine includes closures

I 1980s–: modern functional languages, CEK machine, CPStransform, . . .

I Now (2015): many different compilers for ML and Haskell;C++ has lambda expressions that build closures

Page 8: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Lambda calculus syntax

M ::= x

| M1M2

| λx .M

| n

Here n ranges over constants such as integers.Note: this is an ambiguous grammar, so no good for parsing.Convention: left associative.

M1M2M3

is read as(M1M2)M3

Lambda abstraction extends as far to the right as possible:λx .x y is read as λx .(x y) and not (λx .x) y

Page 9: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Free variables of a lambda term

In an abstractionλx .M

the scope of x is M.A variable is free in a lambda term if there is an occurrence of thatvariable that is not in scope of a lambda binding for that variable.A lambda term that contains no free variables is called closed.Note: variables in lambda 6= variables in most programminglanguages. The former cannot be updated.

Page 10: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Free variables examples

What are the free variables in:

1. z (x y)

2. λx .x

3. λx .y x

4. λy .λx .y x

5. (λy .λx .y x) x

6. (λx .x) (λy .x) y

Exercise: for each occurrence of a variable, draw an arrow to thecorresponding lambda binding, if there is one.

Page 11: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Free variables examples

What are the free variables in:

1. z (x y)

2. λx .x

3. λx .y x

4. λy .λx .y x

5. (λy .λx .y x) x

6. (λx .x) (λy .x) y

Exercise: for each occurrence of a variable, draw an arrow to thecorresponding lambda binding, if there is one.

Page 12: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Free variables examples

What are the free variables in:

1. z (x y)

2. λx .x

3. λx .y x

4. λy .λx .y x

5. (λy .λx .y x) x

6. (λx .x) (λy .x) y

Exercise: for each occurrence of a variable, draw an arrow to thecorresponding lambda binding, if there is one.

Page 13: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Free variables examples

What are the free variables in:

1. z (x y)

2. λx .x

3. λx .y x

4. λy .λx .y x

5. (λy .λx .y x) x

6. (λx .x) (λy .x) y

Exercise: for each occurrence of a variable, draw an arrow to thecorresponding lambda binding, if there is one.

Page 14: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Free variables examples

What are the free variables in:

1. z (x y)

2. λx .x

3. λx .y x

4. λy .λx .y x

5. (λy .λx .y x) x

6. (λx .x) (λy .x) y

Exercise: for each occurrence of a variable, draw an arrow to thecorresponding lambda binding, if there is one.

Page 15: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Free variables examples

What are the free variables in:

1. z (x y)

2. λx .x

3. λx .y x

4. λy .λx .y x

5. (λy .λx .y x) x

6. (λx .x) (λy .x) y

Exercise: for each occurrence of a variable, draw an arrow to thecorresponding lambda binding, if there is one.

Page 16: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

beta reduction

We write M1[x 7→ M2] for the substitution in M1 of x by M2.Here we assume that the bound variables in M1 do not occur inM2, which can always be made to hold by renaming them.β-reduction:

((λx .M1)M2)→β (M1[x 7→ M2])

This is not efficient if we literally copy M2 for every occurrence ofx .Instead: remember that x refers to M2 in an environment.

Page 17: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

beta reduction and compiler terminology

β-reduction:

((λx .M1)M2)→β (M1[x 7→ M2])

I (λx .M1) called function, callee

I M1 function body

I x formal parameter

I M2 actual parameter

Page 18: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Lambda calculus has first-class functions

Can a function be:

1. passed as a parameter to another function? Yes, e.g.:(λx .M1) (λy .M2)

2. returned as the result of another function? Yes, e.g.:λy .(λx .M1)

3. defined inside another function and thereby have access to itsvariables? Yes, e.g.: λy .λx .y

Page 19: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

The trouble with beta reduction and free variables

Beta reduction by replacing variables with values is fine for penciland paper calculation, as originally intended in the lambda calculus.As we have seen in C, the compiled code for a function should stayfixed.Different calls have different values in stack frames and registers.Consider a term

λx .y x

Here x is our formal parameter. We can expect to be passed somevalue for it using some calling convention (stack or register, say).But what about y? We need some way of knowing what its valueis.In C, we have seen how to find values in memory (and in particularusing the frame pointer).What should a machine for lambda calculus do?

Page 20: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Call by name and call by value

Beta reduction is nondeterministic, as there can be more than oneredex in a term.A programming language needs to fix an evaluation order; comparemaking parsing machines deterministic.Consider the following term with multiple β-redexes R1, R2, andR3:

R1︷ ︸︸ ︷(λx1 .((λx2 .M2)M3︸ ︷︷ ︸

R2

)) ((λx4 .M4)M5︸ ︷︷ ︸R3

)

Under call-by-name, R1 is the next redex to be reduced.Under call-by-value, it is R3.R2 is under a lambda. Reducing R2 correspond to function inliningrather than function call.

Page 21: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Encoding let as lambda

A local let binding

let x = M1 in M2

is encoded as(λx .M2) M1

Idea: evaluate M1, bind the result to x and then evaluate M2.

Page 22: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Programs idealized as lambda terms

Typical C-style program

f1(T1 x1) { return E1; }

...

fn(Tn xn) { return En; }

main() { return E;}

Idealized in lambda calcu-lus

let f1 = λx1 .E1 in

. . .let fn = λxn .En in

E

Exercise: explain how function linlining on the left corresponds totwo beta reduction on the right.

Page 23: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Infinite loops

(λy .42)((λx .xx)(λx .xx))

The same term may produce a constant or loop forever, dependingwhere we choose to perform the beta reduction.

Page 24: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Encoding of pairs

Data structures such as pairs, lists and trees can be encoded in thelambda calculus. The idea is a kind of protocol between a serverthat holds data and clients that need the data.

〈M1,M2〉 = λv .v M1M2

fst = λp .p (λx .λy .x)

snd = λp .p (λx .λy .y)

Exercise: Prove that

fst 〈M1,M2〉 →β M1

snd 〈M1,M2〉 →β M2

Page 25: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Abstract machines for functional languages

I History: Peter Landin’s 1964 paper “The mechanicalevaluation of expressions”

I SECD machine

I Caml originally came from the Categorical Abstract Machine(CAM)

I Caml compiler based on ZINC machine, itself inspired by theKrivine Abstract Machine

I CEK machine is a cleaner version of the SECD machine byFriedman and Felleisen in the 1980s

I S and D are fused into K

I The CEK machine corresponds to CPS compiling

I CPS is related to the SSA form used in LLVM

Page 26: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK machine name

The name CEK is due to the fact that the machine has threecomponents:

I C stands for control or code. Intuitively, it is the expressionthat the machine is currently trying to evaluate.

I E stand for environment. It gives bindings for the freevariables in C .

I K stands for continuation (given that the letter C is alreadyused up). It tells the machine what to do when it is finishedthe with the current C .

Page 27: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK machine is an interpreter

The CEK machine is strictly speaking not a compiler but aninterpreter.The original program, represented as a lambda term, ismanipulated at run time.A real implementation would translate the lambda term intomachine code which the simulates the CEK machine.Nonetheless, the key ideas are stack and closures.

Page 28: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK machine runs lambda terms as programes

The language that the basic CEK machine can interpret is λcalculus with constants n:

M ::= x

| M1M2

| λx .M

| n

More constructs could be added, e.g., exceptions or assignments.

Page 29: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

How to compile lambdas

A closed lambda term can be implemented as a code pointer, as inC.If a lambda term is not closed, the implementation “makes itclosed”, so to speak, by contructing a closure.

Page 30: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Environments

An environment E is a list of the form

x1 7→W1, . . . , xn 7→Wn

that associates the value Wj to variable xj .We write ∅ for the special case when the list is empty.An environent E can be updated with a new binding, giving x thevalue W , which we write as

E [x 7→W ]

We writelookup x inE

For Wi if x = xi

Page 31: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Closures

A closure is of the form

clos(λx .M,E )

Here x is called the parameter, M the body, and E theenvironment of the closure.A value W can be a constant n or a closure:

W ::= n

| clos(λx .M,E )

Page 32: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Objects and closures

In C, a function body has access to parameters (and also globalvariables).With objects, a function has access to members of the surroundingobject.With closures, a function has access to variables in surroundingfunctions.In both objects and closure, there are additional pointers to data.

Page 33: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK frames and stacks

A frame is of the form

F ::= (W ©)

| (© M E )

A continuation K is a stack of frames.If F is a frame and K a continuation, we write F , K for thecontinuation which we get by pushing F onto the top of K .The empty stack is written as �.

Page 34: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK machine steps

〈x | E | K 〉 〈lookup x inE | E | K 〉

〈M1M2 | E | K 〉 〈M1 | E | (© M2 E ) , K )〉

〈λx .M | E | K 〉 〈clos(λx .M,E ) | E | K 〉

〈W | E1 | (© M E2) , K 〉 〈M | E2 | (W ©) , K 〉

〈W | E1 | (clos(λx .M,E2)©) , K 〉 〈M | E2[x 7→W ] | K 〉

Page 35: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK machine steps with pattern matching highlighted

〈x | E | K 〉 〈lookup x inE | E | K 〉

〈M1M2 | E | K 〉 〈M1 | E | (© M2 E ) , K )〉

〈λx .M | E | K 〉 〈clos(λx .M,E ) | E | K 〉

〈W | E1 | (© M E2) , K 〉 〈M | E2 | (W ©) , K 〉

〈W | E1 | (clos(λx .M,E2)©) , K 〉 〈M | E2[x 7→W ] | K 〉

Page 36: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK steps explained 1

1. If the current code is a variable x , we must look it up in theenvironment E .

2. If the current code is an application M1M2, then we proceedto evaluate the M1 in the operator position. M2 is pushedonto the continuation stack. Note that M2 may contain freevariables. For looking them up later, we push the currentenvironment E along with M2.

3. If the current code is a lambda abstraction, we package it upwith the current environment to form a closure. That closureis the value of the expression.

Page 37: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK steps explained 2

4. If the hole in the top frame is on the left, we pop of the termM and its associated environment E , and proceed to evaluateM relative to E . We also push on a new frame that tells uswe still have to apply W to the result we hope to get from theevalutation of M.

5. If the hole in the top frame is on the right, we pop off theframe, which should contain a closure. We apply the closureby evaluating its body in the environment extended with thevalue W for the argument of the closure. If there is no closurein the frame, then the machine gets stuck and there is notransition step. That situation arises if we get a run-time typeerror from ill-typed code such as applying a constant tosomething, as in 7 (λx .x).

Page 38: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Function call (application) in the CEK machine

Evaluating an applicationM1M2

is done in three stages:

1. evaluate M1, while remembering M2 and the currentenvironment in frame (© M2 E )

2. evaluate M2, while remembering the value W1 we got fromM2 in the frame (W1©)

3. When M2 has been evaluated to some W2, pop the frame(W1©) and apply W1 to W2. This only works if W1 is aclosure, say

W1 = clos(λx .M,E )

If so, x gets bound to W2.

This may be a little subtle to understand due to the switchingbetween M1 and M2.

Page 39: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK evaluation

We say that a term M evaluates to a value W if there is asequence of steps:

〈M | ∅ | �〉 · · · 〈W | E | �〉

The end state must have a value in the C position and an emptystack/final continuation K = �.The environment need not be empty.Note: the machine is done when its stack is empty, like the LLmachine.The CEK machine is deterministic.The CEK machine may get stuck.

Page 40: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉

〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 41: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉

〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 42: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉

〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 43: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉

〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 44: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉

〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 45: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉

〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 46: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉

〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 47: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉

〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 48: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉

〈1 | x 7→ 1, y 7→ 2 | �〉

Page 49: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example: function as result and function inside another

((λx .λy .x) 1) 2 evaluates to 1

〈((λx .λy .x) 1) 2 | ∅ | �〉 〈(λx .λy .x) 1 | ∅ | (© 2 ∅)〉 〈(λx .λy .x) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈clos((λx .λy .x), ∅) | ∅ | (© 1 ∅) , (© 2 ∅)〉 〈1 | ∅ | (clos((λx .λy .x), ∅)©) , (© 2 ∅)〉 〈λy .x | x 7→ 1 | (© 2 ∅)〉 〈clos((λy .x), x 7→ 1) | x 7→ 1 | (© 2 ∅)〉 〈2 | ∅ | (clos(λy .x , x 7→ 1)©)〉 〈x | x 7→ 1, y 7→ 2 | �〉 〈1 | x 7→ 1, y 7→ 2 | �〉

Page 50: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉

〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 51: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉

〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 52: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉

〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 53: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉

〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 54: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉

〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 55: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉

〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 56: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉

〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 57: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉

〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 58: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉

〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 59: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉

〈2 | x 7→ 2 | �〉

Page 60: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2: function as parameter

(λf .f 2) (λx .x) evaluates to 2

〈(λf .f 2) (λx .x) | ∅ | �〉 〈(λf .f 2) | ∅ | (© (λx .x) ∅) ,�〉 〈clos((λf .f 2), ∅) | ∅ | (© (λx .x) ∅) ,�〉 〈λx .x | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈clos(λx .x , ∅) | ∅ | (clos((λf .f 2), ∅)©) ,�〉 〈 f 2 | f 7→ clos(λx .x , ∅) | �〉 〈 f | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈clos(λx .x , ∅) | f 7→ clos(λx .x , ∅) | (© 2 f 7→ clos(λx .x , ∅)) ,�〉 〈2 | f 7→ clos(λx .x , ∅) | (clos(λx .x , ∅)©) ,�〉 〈x | x 7→ 2 | �〉 〈2 | x 7→ 2 | �〉

Page 61: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 3: machine gets stuck

5 (λx .x) is nonsense. You cannot apply a number to a function.

〈5 (λx .x) | ∅ | �〉

〈5 | ∅ | (© (λx .x) ∅) ,�〉 〈(λx .x) | ∅ | (5©) ,�〉 〈clos((λx .x), ∅) | ∅ | (5©) ,�〉

Does not match the rule, as 5 is not a closure.

〈W | E1 | (clos(λx .M,E2)©) , K 〉 〈M | E2[x 7→W ] | K 〉

In ML, it would be rejected by the type checker. In Lisp/Scheme,you get a runtime error.

Page 62: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 3: machine gets stuck

5 (λx .x) is nonsense. You cannot apply a number to a function.

〈5 (λx .x) | ∅ | �〉 〈5 | ∅ | (© (λx .x) ∅) ,�〉

〈(λx .x) | ∅ | (5©) ,�〉 〈clos((λx .x), ∅) | ∅ | (5©) ,�〉

Does not match the rule, as 5 is not a closure.

〈W | E1 | (clos(λx .M,E2)©) , K 〉 〈M | E2[x 7→W ] | K 〉

In ML, it would be rejected by the type checker. In Lisp/Scheme,you get a runtime error.

Page 63: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 3: machine gets stuck

5 (λx .x) is nonsense. You cannot apply a number to a function.

〈5 (λx .x) | ∅ | �〉 〈5 | ∅ | (© (λx .x) ∅) ,�〉 〈(λx .x) | ∅ | (5©) ,�〉

〈clos((λx .x), ∅) | ∅ | (5©) ,�〉

Does not match the rule, as 5 is not a closure.

〈W | E1 | (clos(λx .M,E2)©) , K 〉 〈M | E2[x 7→W ] | K 〉

In ML, it would be rejected by the type checker. In Lisp/Scheme,you get a runtime error.

Page 64: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 3: machine gets stuck

5 (λx .x) is nonsense. You cannot apply a number to a function.

〈5 (λx .x) | ∅ | �〉 〈5 | ∅ | (© (λx .x) ∅) ,�〉 〈(λx .x) | ∅ | (5©) ,�〉 〈clos((λx .x), ∅) | ∅ | (5©) ,�〉

Does not match the rule, as 5 is not a closure.

〈W | E1 | (clos(λx .M,E2)©) , K 〉 〈M | E2[x 7→W ] | K 〉

In ML, it would be rejected by the type checker. In Lisp/Scheme,you get a runtime error.

Page 65: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 4: machine gets stuck

A free variable that does not occur in the environment makes themachine get stuck.

〈x | ∅ | �〉

In ML, this would be a compile-time error and in Lisp/Scheme arun-time error.The type system of ML prevents all such run-time errors;Milner’s slogan for ML, ”Well-typed programs do not go wrong.”

Page 66: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Examples as above in OCaml

# (fun x -> fun y -> x) 1 2;;

- : int = 1

# (fun f -> f 2) (fun x -> x);;

- : int = 2

# 5 (fun x -> x);;

Error: This expression is not a function;

it cannot be applied

# x;;

Error: Unbound value x

Page 67: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Exercise

Suppose we do not build closures at all, and we just pass aroundterms like λx .M instead. How would that affect the semantics ofthe language?

Page 68: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Exercise

Explain what sequence of steps the CEK machine performs startingfrom the following configuration:

〈(λx .xx) (λx .xx) | ∅ | �〉

In particular, does one get a W at the end?

Page 69: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Stretch exercise

Implement the CEK machine in your favourite programminglanguage.C, OCaml, Haskell, and Agda are very suitable.

Page 70: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Advanced programming language features

exceptions: C++ adapted them from ML, now mainstreamgarbage collection: first in Lisp, then other functional languages,became mainstream in Javaclosures: C++11 and Java

Page 71: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK machine with control operators here and go

We extend the programming language with two control operators:

M ::= . . .

| go n

| hereM

Intuitively, go jumps to the nearest enclosing here.This in an idealized version of exceptions in Ocaml, C++, Java,. . . .

Page 72: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Compare exceptions in OCaml

The control we have added to the CEK machine is like a singleexception of integer type in OCaml, such that all exceptionhandlers are the identity.

exception E of int;;

(go n) = raise (E n)

(hereM) = try M with E x -> x

Page 73: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Stack frames extended for control

To give meaning to the control operators, we add a new kind offrame. It just marks a position on the stack:

F ::= . . . | II

The CEK+go machine with control has these additional transitionsteps:

〈hereM | E | K 〉 〈M | E | II , K 〉 (1)

〈go n | E | K1 ,II , K2 〉 〈n | E | K2 〉 (2)

〈W | E | II , K 〉 〈W | E | K 〉 (3)

Here K1 does not contain II, that is,

K1 6= K3 ,II , K4

for any K3 and K4.

Page 74: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

The here and go rules explained

1. A term hereM is evaluated by pushing the marker onto thestack and continuing with evaluating M.

2. A term goM is evaluated by erasing the stack up to thenearest marker, and then proceeding with evaluating M.

3. When a value W is produced by the evaluation, any markeron the top of the stack is popped off and ignored.

Page 75: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

CEK machine with control operators here and go

〈x | E | K 〉 〈lookup x inE ) | E | K 〉〈M1M2 | E | K 〉 〈M1 | E | (© M2 E ) , K )〉〈λx .M | E | K 〉 〈clos(λx .M,E ) | E | K 〉

〈W | E1 | (© M E2) , K 〉 〈M | E2 | (W ©) , K 〉〈W | E1 | (clos(λx .M,E2)©) , K 〉 〈M | E2[x 7→W ] | K 〉

〈hereM | E | K 〉 〈M | E | II , K 〉〈go n | E | K1 ,II , K2 〉 〈n | E | K2 〉

〈W | E | II , K 〉 〈W | E | K 〉

Page 76: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 1 of jumping with here and go

〈here ((λx .2) (go 5)) | ∅ | �〉

〈(λx .2) (go 5) | ∅ | II ,�〉

〈(λx .2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈clos(λx .2, ∅) | ∅ | (© (go 5) ∅) ,II ,�〉

〈(go 5) | ∅ | (clos(λx .2, ∅)©) ,II ,�〉

〈5 | ∅ | �〉

The go 5 has deleted the (λx .2).

Page 77: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 1 of jumping with here and go

〈here ((λx .2) (go 5)) | ∅ | �〉

〈(λx .2) (go 5) | ∅ | II ,�〉

〈(λx .2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈clos(λx .2, ∅) | ∅ | (© (go 5) ∅) ,II ,�〉

〈(go 5) | ∅ | (clos(λx .2, ∅)©) ,II ,�〉

〈5 | ∅ | �〉

The go 5 has deleted the (λx .2).

Page 78: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 1 of jumping with here and go

〈here ((λx .2) (go 5)) | ∅ | �〉

〈(λx .2) (go 5) | ∅ | II ,�〉

〈(λx .2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈clos(λx .2, ∅) | ∅ | (© (go 5) ∅) ,II ,�〉

〈(go 5) | ∅ | (clos(λx .2, ∅)©) ,II ,�〉

〈5 | ∅ | �〉

The go 5 has deleted the (λx .2).

Page 79: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 1 of jumping with here and go

〈here ((λx .2) (go 5)) | ∅ | �〉

〈(λx .2) (go 5) | ∅ | II ,�〉

〈(λx .2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈clos(λx .2, ∅) | ∅ | (© (go 5) ∅) ,II ,�〉

〈(go 5) | ∅ | (clos(λx .2, ∅)©) ,II ,�〉

〈5 | ∅ | �〉

The go 5 has deleted the (λx .2).

Page 80: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 1 of jumping with here and go

〈here ((λx .2) (go 5)) | ∅ | �〉

〈(λx .2) (go 5) | ∅ | II ,�〉

〈(λx .2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈clos(λx .2, ∅) | ∅ | (© (go 5) ∅) ,II ,�〉

〈(go 5) | ∅ | (clos(λx .2, ∅)©) ,II ,�〉

〈5 | ∅ | �〉

The go 5 has deleted the (λx .2).

Page 81: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 1 of jumping with here and go

〈here ((λx .2) (go 5)) | ∅ | �〉

〈(λx .2) (go 5) | ∅ | II ,�〉

〈(λx .2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈clos(λx .2, ∅) | ∅ | (© (go 5) ∅) ,II ,�〉

〈(go 5) | ∅ | (clos(λx .2, ∅)©) ,II ,�〉

〈5 | ∅ | �〉

The go 5 has deleted the (λx .2).

Page 82: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2 of jumping with here and go

〈here ((go 2) (go 5)) | ∅ | �〉

〈(go 2) (go 5) | ∅ | II ,�〉

〈(go 2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈2 | ∅ | �〉

The go 2 happens first and deletes the go 5 due to left to rightevaluation.

Page 83: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2 of jumping with here and go

〈here ((go 2) (go 5)) | ∅ | �〉

〈(go 2) (go 5) | ∅ | II ,�〉

〈(go 2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈2 | ∅ | �〉

The go 2 happens first and deletes the go 5 due to left to rightevaluation.

Page 84: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2 of jumping with here and go

〈here ((go 2) (go 5)) | ∅ | �〉

〈(go 2) (go 5) | ∅ | II ,�〉

〈(go 2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈2 | ∅ | �〉

The go 2 happens first and deletes the go 5 due to left to rightevaluation.

Page 85: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 2 of jumping with here and go

〈here ((go 2) (go 5)) | ∅ | �〉

〈(go 2) (go 5) | ∅ | II ,�〉

〈(go 2) | ∅ | (© (go 5) ∅) ,II ,�〉

〈2 | ∅ | �〉

The go 2 happens first and deletes the go 5 due to left to rightevaluation.

Page 86: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Example 3 of jumping with here and go

A go without a surrounding here is stuck.

〈(go n) | E | K 〉

This corresponds to an uncaught exception in ML. The typesystem does not prevent this.In Java, throws clauses try to minimize uncaught checkedexceptions at compile time.

Page 87: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Exercise

Evaluate the following term in the CEK machine

(λf . here ((λx .1) (f 2))) (here (λy . go y))

You should pay particular attention to which of the twooccurrences of here is jumped to. The one on the left isdynamically enclosing (when the go is evaluated), whereas the oneon the right is statically enclosing (where the go is defined).

Page 88: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Exercise

Define a version of the CEK machine that evaluates from left toright, so that in

M1 M2

the argument M2 is evaluated before M1.Use here and go examples to observe the evaluation order.

Page 89: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Compare exceptions in OCaml

The control we have added to the CEK machine is like a singleexception of integer type in OCaml, such that all exceptionhandlers are the identity.

exception E of int;;

(go n) = raise (E n)

(hereM) = try M with E x -> x

Page 90: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Exceptions in OCaml and evaluation order

We can observe that OCaml does right-to-left evaluation:

exception E of int;;

(raise (E 1)) (raise (E 2));;

Or, since uncaught exceptions are grungy, we could add a handler:

try (raise (E 1)) (raise (E 2)) with E x -> x;;

This gives

- : int = 2

Page 91: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Compare exceptions in OCaml: static vs dynamic

exception E;;

let f =

try

fun x -> raise E

with E -> fun y -> "static"

in

try

f 0

with E -> "dynamic"

;;

Exercise: calculate this example in the CEK machine.Exercise: translate this example using lambda into C++ or Java.

Page 92: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Optimizations, lambda calculus and the CEK machine

I Let’s revisit optimizations in the light of what we have learnedabout lambda and CEK

I The CEK machine gives us a formal model in which we canprove that optimizations are correct.

I Formally: optimizations preserve contextual equivalence.

I Constant propagation is like a beta reduction.

I Function inlining is like two beta reductions.

I On the other hand, the CEK machine is too high-level to dotail call optimization.

I Current (2010–) research: verify optimizations in LLVM; C++optimizations are not valid due to concurrency.

Page 93: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Encoding let as lambda

Naming intermediate values with let is useful for optimizations.Recall that a local let binding

let x = M1 in M2

is encoded as(λx .M2) M1

Idea: evaluate M1, bind the result to x and then evaluate M2.

Page 94: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Optimization example 1: constant propagation

let x = V in . . . x . . .

can be optimized to

let x = V in . . .V . . .

This is easier in functional than imperative languages.int x = 42; x = x + 2; y = x

Page 95: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Optimization example 2: function inlining

let f = λx .M in . . . f V . . .

can be optimized to

let f = λx .M in . . .M[x 7→ V ] . . .

where M[x 7→ V ] is the substitution of the actual parameter V forthe formal parameter x on the body M of the function f .

Page 96: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Function inlining from Clang lectures revisited

long s(long x)

{

return x * x;

}

long f(long y)

{

return s(y + 1);

}

let s = λx .x ∗ x in

let f = λy .s(y + 1) in

M

let s = λx .x ∗ x in let f = λy .s(y + 1) in M

= (λs .(λf .M) (λy .s(y + 1))) (λx .x ∗ x)

→β (λf .M) (λy .(λx .x ∗ x) (y + 1)))

→β (λf .M) (λy .(y + 1) ∗ (y + 1))

= let f = λy .(y + 1) ∗ (y + 1) in M

Page 97: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Function inlining from Clang lectures revisited

long s(long x)

{

return x * x;

}

long f(long y)

{

return s(y + 1);

}

let s = λx .x ∗ x in

let f = λy .s(y + 1) in

M

let s = λx .x ∗ x in let f = λy .s(y + 1) in M

= (λs .(λf .M) (λy .s(y + 1))) (λx .x ∗ x)

→β (λf .M) (λy .(λx .x ∗ x) (y + 1)))

→β (λf .M) (λy .(y + 1) ∗ (y + 1))

= let f = λy .(y + 1) ∗ (y + 1) in M

Page 98: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Function inlining from Clang lectures revisited

long s(long x)

{

return x * x;

}

long f(long y)

{

return s(y + 1);

}

let s = λx .x ∗ x in

let f = λy .s(y + 1) in

M

let s = λx .x ∗ x in let f = λy .s(y + 1) in M

= (λs .(λf .M) (λy .s(y + 1))) (λx .x ∗ x)

→β (λf .M) (λy .(λx .x ∗ x) (y + 1)))

→β (λf .M) (λy .(y + 1) ∗ (y + 1))

= let f = λy .(y + 1) ∗ (y + 1) in M

Page 99: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Function inlining from Clang lectures revisited

long s(long x)

{

return x * x;

}

long f(long y)

{

return s(y + 1);

}

let s = λx .x ∗ x in

let f = λy .s(y + 1) in

M

let s = λx .x ∗ x in let f = λy .s(y + 1) in M

= (λs .(λf .M) (λy .s(y + 1))) (λx .x ∗ x)

→β (λf .M) (λy .(λx .x ∗ x) (y + 1)))

→β (λf .M) (λy .(y + 1) ∗ (y + 1))

= let f = λy .(y + 1) ∗ (y + 1) in M

Page 100: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Function inlining from Clang lectures revisited

long s(long x)

{

return x * x;

}

long f(long y)

{

return s(y + 1);

}

let s = λx .x ∗ x in

let f = λy .s(y + 1) in

M

let s = λx .x ∗ x in let f = λy .s(y + 1) in M

= (λs .(λf .M) (λy .s(y + 1))) (λx .x ∗ x)

→β (λf .M) (λy .(λx .x ∗ x) (y + 1)))

→β (λf .M) (λy .(y + 1) ∗ (y + 1))

= let f = λy .(y + 1) ∗ (y + 1) in M

Page 101: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Function inlining from Clang lectures revisited

long s(long x)

{

return x * x;

}

long f(long y)

{

return s(y + 1);

}

let s = λx .x ∗ x in

let f = λy .s(y + 1) in

M

let s = λx .x ∗ x in let f = λy .s(y + 1) in M

= (λs .(λf .M) (λy .s(y + 1))) (λx .x ∗ x)

→β (λf .M) (λy .(λx .x ∗ x) (y + 1)))

→β (λf .M) (λy .(y + 1) ∗ (y + 1))

= let f = λy .(y + 1) ∗ (y + 1) in M

Page 102: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Function inlining from Clang lectures revisited

long s(long x)

{

return x * x;

}

long f(long y)

{

return s(y + 1);

}

let s = λx .x ∗ x in

let f = λy .s(y + 1) in

M

let s = λx .x ∗ x in let f = λy .s(y + 1) in M

= (λs .(λf .M) (λy .s(y + 1))) (λx .x ∗ x)

→β (λf .M) (λy .(λx .x ∗ x) (y + 1)))

→β (λf .M) (λy .(y + 1) ∗ (y + 1))

= let f = λy .(y + 1) ∗ (y + 1) in M

Page 103: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Beta reduction as an optimizaton

Models of Computation: Church Rosser and confluence: you canbeta reduce a lambda anywhere inside an expression, withoutchanging the resultIn call-by-value with effects (like assignment or control), we needto be more careful. Unrestricted beta reduction is not a soundoptimization in the CEK machine!We cannot optimize

(λx .5) ((λx .xx) (λx .xx))

or(λx .5) (go 2)

into5

Need to be careful about effects and use beta-value instead.

Page 104: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Verfying compiler optimizations

If the compiler optimizes M1 into M2, then they should becontextually equivalent, so the user never sees any differencebetween the optimized and unoptimized program.Example: beta value

(λx .M3) (λy .M4)→ M3[x 7→ λy .M4]

This may seem obvious, but is not so easy to prove (simulationproof).Verifting compiler optimizations, including LLVM, is an activeresearch area.

Page 105: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Contextual equivalence as correctness of optimzations

For the CEK machine, we write M ⇓ n if

〈M | ∅ | �〉 · · · 〈n | E | �〉

A context C is a “term with a hole”:

C ::= ©| M C

| C M

| λx .C

We write C [M] for the term that we get by plugging M into thehole position © in C .M1 and M2 are contextually equivalent if for all contexts C , andintegers n

C [M1] ⇓ n if and only if C [M2] ⇓ n

Page 106: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Intermediate languages

I Intermediate languages are used for optimizations

I All intermediate values are named.

I All control flow is made explicit with jumps and labels.

I This format is good for optimizations and code generation:

I named values 7→ registers

I labels 7→ code location

I Both SSA and CPS do this.

I SSA = static single assignment, used in LLVM

I CPS = continuation passing style, used in functionallanguages

Page 107: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Some current research in compilers

I There is lots of research, but here are some areas that I amaware of.

I Semantics of intermediate languages, like LLVM IR usingabstract machines.

I Verification of optimizations.

I SSA = static single assignment, used in LLVM

I CPS = continuation passing style, used in functionallanguages

I If you are interested in a PhD on compilers, feel free to askme.

Page 108: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Further reading

[ABDM03] gives an overview of abstract machines and simplecompilers derived from them[Ken07] gives an overview of modern CPS compilation

Mads Sig Ager, Dariusz Biernacki, Olivier Danvy, and JanMidtgaard.From interpreter to compiler and virtual machine: a functionalderivation.BRICS, Department of Computer Science, University ofAarhus, 2003.

Andrew Kennedy.Compiling with continuations, continued.In ACM SIGPLAN Notices, volume 42, pages 177–190. ACM,2007.

Page 109: Implementing functional languages with abstract machineshxt/2015/compilers/compiling-functiona… · Structure of the module Parsing X IProgression from: Language + Logic, Models

Structure of the module

Parsing X

I Progression from: Language + Logic, Models of Computation

I abstract machines, formal,“mathy”

Compiling C with Clang X

I Progression from: Computer Systems + Architecture, C/C++

I not so formal, by example, x86 machine code

Implementing functional languages X

I Progression from: functional programming

I builds on abstract machines and C stack

I the most research-led section, goes beyond Dragon Book


Recommended