Continuations and Delayed Evaluation in Programming - Prof. Laura Dillon, Study notes of Programming Languages

The concepts of continuations and delayed evaluation in programming. Continuations are functions that represent the rest of the program and are used in various programming paradigms such as lisp and ml compilation, operating systems, and web application development. Delayed evaluation is a technique used to defer a computation until it is actually needed, which can save resources and improve performance. Examples and explanations of how these concepts are used in practice.

Typology: Study notes

Pre 2010

Uploaded on 07/28/2009

koofers-user-vej
koofers-user-vej 🇺🇸

10 documents

1 / 8

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
L. Dillon, CSE 452, Fall 2008 1
Control in Sequential Languages
Structured Programming
Go to considered harmful
Exceptions
“structured” jumps that may return a value
dynamic scoping of exception handler
Continuations
Function representing the rest of the program
Generalized form of tail recursion
Functions and evaluation order
Control evaluation order using function definitions and calls
L. Dillon, CSE 452, Fall 2008 2
Idea:
The continuation of an expression is “the remaining work to be
done after evaluating the expression”
Continuation of expression e is a function; normally applied to e
General programming technique
Capture the continuation at some point in a program
Use it later: “jump” or “exit” by function call
Usefulin
Compiler optimization: make control flow explicit
Operating system scheduling, multiprogramming
Web programming
Continuations
L. Dillon, CSE 452, Fall 2008 3
Example: Roots of a quadratic equation
Version 0: without any continuations
exception notQuadratic;
exception imaginaryRoots;
fun equal(x:real, y:real) = x <= y andalso x >= y;
fun roots(a, b, c) =
let
val discBase = (b*b) - (4.0*a*c)
val denom = 2.0*a
in
if equal(denom, 0.0) then raise notQuadratic
else if discBase < 0.0 then raise imaginaryRoots
else let
val disc = Math.sqrt(discBase)
in
if disc > 0.0 then [(~b + disc)/denom, (~b - disc)/denom]
else [~b/denom]
end
end;
L. Dillon, CSE 452, Fall 2008 4
Example: Roots of a quadratic equation
Version 1: Uses a normal continuation and an error continuation
fun checkQuad (x, n_continuation, e_continuation) =
if equal(x, 0.0) then e_ continuation() else n_continuation(x);
fun roots1(a, b, c) =
let fun econt () = raise notQuadratic
fun ncont (x) =
let val discBase = (b*b) - (4.0*a*c)
in
if discBase < 0.0 then raise imaginaryRoots
else let val disc = Math.sqrt(discBase)
in
if disc>0.0 then [(~b + disc)/x, (~b - disc)/x]
else [~b/x]
end
end
in
checkQuad(2.0* a, ncont, econt)
end;
pf3
pf4
pf5
pf8

Partial preview of the text

Download Continuations and Delayed Evaluation in Programming - Prof. Laura Dillon and more Study notes Programming Languages in PDF only on Docsity!

L. Dillon, CSE 452, Fall 2008

1

Control in Sequential Languages

Structured Programming

Go to considered harmful

Exceptions−

“structured” jumps that may return a value

dynamic scoping of exception handler

Continuations−

Function representing the rest of the program

Generalized form of tail recursion

Functions and evaluation order−

Control evaluation order using function definitions and calls

L. Dillon, CSE 452, Fall 2008

Idea:

The

continuation

of an expression is “the remaining

work to be

Continuation of expressiondone after evaluating the expression”

e

is a function; normally applied to

e

General

programming technique

Capture the continuation at some point in a program

Use it later: “jump” or “exit” by function call

Useful−

in

Compiler optimization: make control flow explicit

Operating system scheduling, multiprogramming

Web programming

Continuations

L. Dillon, CSE 452, Fall 2008

3

Example: Roots of a quadratic equation

exceptionVersion 0: without any continuations

notQuadratic;

exception

imaginaryRoots;

fun

equal(x:real,

y:real)

x

y

andalso

x

y;

fun

roots(a,

b,

c)

let

val

discBase

(b*b)

(4.0ac)

val

denom

2.0*a

in

if

equal(denom,

then

raise

notQuadratic

else

if

discBase

then

raise

imaginaryRoots

else

let

val

disc

Math.sqrt(discBase)

in

if

disc

then

[

(~b

disc)/denom,

(~b

disc)/denom]

else

[~b/denom]

end

end;

L. Dillon, CSE 452, Fall 2008

Example: Roots of a quadratic equation

Version 1: Uses a

normal continuation

and an

error continuation

fun

checkQuad

(x,

n_continuation,

e_continuation)

if

equal(x,

then

e_continuation()

else

n_continuation(x);

fun

roots1(a,

b,

c)

let

fun

econt

raise

notQuadratic

fun

ncont

(x)

let

val

discBase

(b*b)

(4.0ac)

in

if

discBase

then

raise

imaginaryRoots

else

let

val

disc

Math.sqrt(discBase)

in

if

disc>0.

then

[

(~b

disc)/x,

(~b

disc)/x]

else

[~b/x]

end

end

in

checkQuad(2.0*a,

ncont,

econt)

end;

L. Dillon, CSE 452, Fall 2008

5

Example: Roots of a quadratic equation

funVersion 2: Like version 1, uses normal and error continuations

checkImaginary

(x,

n_continuation,

e_continuation)

if

x

then

e_continuation()

else

n_continuation(Math.sqrt(x));

fun

roots2(a,

b,

c)

let

fun

econt

raise

notQuadratic

fun

ncont

(x)

let

fun

econt

raise

imaginaryRoots

fun

ncont

(disc)

if

disc

then

[

(~b

disc)/x,

(~b

disc)/x]

else

[~b/x]

in

checkImaginary(b*b

4.0ac,

ncont,

econt)

end

in

checkQuad(2.0*a,

ncont,

econt)

end;

L. Dillon, CSE 452, Fall 2008

Example: Roots of a quadratic equation

funVersion 3: Uses continuations to calculate the roots

checkNumRoots(disc,

continuation1,

continuation2)

if

disc

then

continuation1(disc)

else

continuation2();

fun

roots3(a,

b,

c)

let

fun

econt

raise

notQuadratic

fun

ncont

(x)

let

fun

econt

raise

imaginaryRoots

fun

ncont

(disc)

let

fun

con

(disc)

[

(~b

disc)/x,

(~b

disc)/x]

fun

con

[~b/x]

in

checkNumRoots(disc,

con1,

con2)

end

in

checkImaginary(b*b

4.0ac,

ncont,

econt)

end

in

checkQuad(2.0*a,

ncont,

econt)

end;

L. Dillon, CSE 452, Fall 2008

7

Standard definition:^ Continuation-passing form (CPF) & tail recursion

fun

fac(n)

if

n

then

else

n

fac(n-1);

Tail

-recursive version:

fun

fac(n)

let

fun

f(n,k)

if

n

then

k

else

f(n-1,

n*k)

in

f(n,1)

end;

Standard definition:

fun

digits(n)

if

n

then

else

digits(n

div

Tail

-recursive version:

fun

digits(n)

let

fun

d(n,k)

if

n

then

k

else

d(n

div

k)

in

d(n,1)

end;

  • Optimize continuation functions to single integer – Transform to continuation-passing form How could we derive these?

of fac.)of the tail-recursive version (See Mitchell for derivation

L. Dillon, CSE 452, Fall 2008

Continuation-passing form (CPF) & tail recursion

The CPF of a function

f

of

n

arguments is a function

f

cpf

of

n+

The last argument to arguments.

f

cpf

is a continuation, which is to be applied to

the value returned by applying

f

to the first

n

arguments.

That is:

f

cpf

x

1

, x

2

, ..., x

n

, k

k

f

x

1

, x

2

, ..., x

n

Observation:

f

cpf

x

1

, x

2

, ..., x

n

m

y.y

m

y.y

f

x

1

, x

2

, ..., x

n

f

x

1

, x

2

, ..., x

n

L. Dillon, CSE 452, Fall 2008

13

Capturing the “current continuation”

Recall: The

continuation

of an expression

e

is an

abstraction of what the system will do with the value of

e

e.g.

, continuation of

x*x

in

sqrt(xx+yy)

is

m

z.sqrt(z+y*y)

SML/NJ

provides a structure (library module) for

capturing

” a continuation for later use (application):

structure

SMLofNJ.Cont

sig

type

ʻa

cont

val

callcc

(ʻa

cont

ʻa)

ʻa

val

throw

ʻa

cont

ʻa

ʻb

end

To

use it:

-open

SMLofNJ.Cont;

L. Dillon, CSE 452, Fall 2008

Capturing the “current continuation”

type

ʻa

cont

The

type of continuations accepting arguments of type

ʻa

callcc

f

Capture

the current configuration,

cc

, and apply

f

to it; if

f

executes a throw

instruction with

cc

and argument

x

, then

callcc

f

returns

x

as a result; otherwise it returns the value returned by

f

throw

k

a

Throw

continuation

k

with argument

a

Example:

val

x

int

callcc(fn

k

if

x

then

x

else

throw

k

val

x

int

callcc(fn

k

if

x

then

x

else

throw

k

L. Dillon, CSE 452, Fall 2008

15

Example

callcc(fn

k

callcc(fn

k

if

then

(throw

k

else

(throw

k

“stuck”)

Intuition

  • Throw lets you jump to that point and continue from there– Callcc lets you mark a point in program that you can return to•

More with callcc

L. Dillon, CSE 452, Fall 2008

OS kernel schedules multiple threads

Each thread may have a separate stack

Stack of blocked thread is stored within the kernel

Mach−

“continuation” approach

Blocked

thread represented as

Pointer to a continuation function, list of arguments

Stack is discarded when thread blocks

Programming◊

implications

System call such as

msg_recv

can block

Kernel code calls

msg_recv

with continuation passed as an argument

Advantage

/Disadvantage

Saves

a lot of space, need to write “continuation” functions

Continuations in Mach OS

L. Dillon, CSE 452, Fall 2008

17

Continuations in web programming

Asynchronous XHR similar to continuations:

function

callWithContinuation(url,

k)

var

xhr

new

XMLHttpRequest();

xhr.open(ʻGETʼ

url,

true);

xhr.onreadystatechange

function

if

(xhr.readyState

k(xhr.responseText);

xhr.send(null);}

Usage:

callWithContinuation(ʻhttp://a.com/describe?id=10ʼ

alert);

  • Basis of AJAX Web programming paradigm • Client continues while server runs

L. Dillon, CSE 452, Fall 2008

  1. Translation to1) Lexical analysis, parsing, type checking SML continuation-based compiler [Appel, Steele]

m

-calculus form

7) Register spilling – no expression with more than6) Elimination of nested scopes5) Closure conversion – eliminate free variables4) Optimization of CPS3) Conversion to continuation-passing style (CPS)

n

free vars

9) Assemble to produce target-machine program8) Generation of target assembly language program

Continuations in compilation

L. Dillon, CSE 452, Fall 2008

19

Functions and evaluation order

Evaluation of ML expression is

eager

Call-

by-value: evaluate args to a function before application

Inefficient

if the values of some arguments are not needed

during evaluation of the function body

Other evaluation strategies

Call-

by-reference: pass L-values of args to the function

To access the value of a formal involves extra level of indirection

Leads to aliasing, complications on abnormal termination, etc.

Call-by-need◊

: Pass function (closure) with which to compute the

value of an arg, when/if it is needed—called

lazy evaluation

Optimization:

memoize

an argument value when it is first used, avoid

recalculating it on subsequent uses

L. Dillon, CSE 452, Fall 2008

Delay and Force (Version #1)

Macros that implement call-by-need in a language with eager

E.g.,evaluation, static scoping and HO functions

to pass

x

eagerly (by-value) and

y

lazily (by-need)

fun

f(x,

y)

x

Force(y)

f(e1,

Delay(e2));

Implementing

Delay

and

Force

in ML

Delay(e)

fn()

e

Force(e)

e()

Example

exception

NegVal

of

real;

fun

expensive(x)

fun

foo(x,

y)

if

x

then

Math.pow(x,y())

else

raise

NegVal(x);

foo(~1.0,

fn()=>expensive(10.0));

foo(1.0,

fn()=>expensive(10.0));

L. Dillon, CSE 452, Fall 2008

25

Delay and Force (Version #2)

Suppose the delayed value is needed more than once in

If theevaluating the function body.

argument is pure (no side-effects), would like to

avoid re-evaluating the argument:

Represent

argument using

memoization

(common design idiom)

Flag: indicates if the argument has been evaluated previously or not

datatype

ʻa

delay

EV

of

ʻa

UN

of

unit

ʻa;

Value:

value of the actual argument;Initially, a parameter-less function (closure) that, when applied, returns the

Delay(e)

ref(UN(fn()

e)

After the first time the argument is evaluated, the value of the argument

fun

ev(EV(x))

x

ev(UN(f))

f();

fun

force(d)

let

val

v

ev(!d)

in

(d

EV(v);

v)

end;

L. Dillon, CSE 452, Fall 2008

How does it work?

datatype

ʻa

delay

EV

of

ʻa

UN

of

unit

ʻa;

ev:

ʻa

delay

ʻa

fun

ev(EV(x))

x

ev(UN(f))

f();

force:

ʻa

delay

ref

ʻa

fun

force(d)

let

val

v

ev(!d)

in

(d

EV(v);

v)

end;

lazy_poly:

real

delay

ref

int

real

fun

lazy_poly(x,n)

if

n<

then

else

Math.pow(force(x),real(n))

lazy_poly(x,n-1);

expensive:

int

real

fun

expensive(x)

lazy_poly(ref(UN(fn()

expensive(7))),

assume:

expensive(7)

(lazy_...)

...

n: x:

(force(x))

...

v: d:

(ev(!d))

...

f:

(f())

...

(expen...)

...

x:

7

UN

a :

a

:PC

EP:

L. Dillon, CSE 452, Fall 2008

27

How does it work?

datatype

ʻa

delay

EV

of

ʻa

UN

of

unit

ʻa;

ev:

ʻa

delay

ʻa

fun

ev(EV(x))

x

ev(UN(f))

f();

force:

ʻa

delay

ref

ʻa

fun

force(d)

let

val

v

ev(!d)

in

(d

EV(v);

v)

end;

lazy_poly:

real

delay

ref

int

real

fun

lazy_poly(x,n)

if

n<

then

else

Math.pow(force(x),real(n))

lazy_poly(x,n-1);

expensive:

int

real

fun

expensive(x)

lazy_poly(ref(UN(fn()

expensive(7))),

assume:

expensive(7)

(lazy_...)

...

n: x:

(force(x))

...

v: d:

(ev(!d))

...

f:

(f())

...

(expen...)

...

x:

7

UN

a :

a

EV

:PC

EP:

L. Dillon, CSE 452, Fall 2008

How does it work?

datatype

ʻa

delay

EV

of

ʻa

UN

of

unit

ʻa;

ev:

ʻa

delay

ʻa

fun

ev(EV(x))

x

ev(UN(f))

f();

force:

ʻa

delay

ref

ʻa

fun

force(d)

let

val

v

ev(!d)

in

(d

EV(v);

v)

end;

lazy_poly:

real

delay

ref

int

real

fun

lazy_poly(x,n)

if

n<

then

else

Math.pow(force(x),real(n))

lazy_poly(x,n-1);

expensive:

int

real

fun

expensive(x)

lazy_poly(ref(UN(fn()

expensive(7))),

assume:

expensive(7)

(lazy_...)

...

n: x:

(force(x))

...

v: d:

(ev(!d))

...

f:

(f())

...

(expen...)

...

x:

7

UN

a :

a

EV

(lazy_...)

...

n: x:

(force(x))

...

v: d:

(ev(!d))

...

x:

EP:

:PC

L. Dillon, CSE 452, Fall 2008

Structured Programming

Go to considered harmful

Exceptions−

“structured” jumps that may return a value

dynamic scoping of exception handler

Continuations−

Function representing the rest of the program

Generalized form of tail recursion

Used in Lisp and ML compilation, some OS projects, web appli-

cation development, …

Delay and force

Used to delay a computation until it is needed

Summary