Control

56
Control in Sequential Languages + some discussion of functional programming John Mitchell CS 242 Reading: Chapter 8, Sections 8.1 – 8.3 (only) Chapter 4, Section 4.4 (only) Fall 2008

description

 

Transcript of Control

Page 1: Control

Control in Sequential Languages+ some discussion of functional programming

John Mitchell

CS 242

Reading: Chapter 8, Sections 8.1 – 8.3 (only)Chapter 4, Section 4.4 (only)

Fall 2008

Page 2: Control

JavaScript blocks and scopes

{ } groups JavaScript statements• Does not provide a separate scope

Blocks w/scope can be expressed using function • (function(){ … })() - create function of no args and

call• Example var y=0; (function () { // begin block

var x=2; // local variable x

y = y+x; }) (); // end block

RECAP

Page 3: Control

Homework 1, Problem 6var x = 5; function f(y) {return (x+y)-2};function g(h){var x = 7; return

h(x)}; {var x = 10; g(f)};

var x = 5; function f(y) {return (x+y)-2}; function g(h){var x = 7; return

h(x)}; {var x = 10; g(f)}; (function (){

var x = 5; (function (){ function f(y) {return (x+y)-2}; (function (){ function g(h){var x = 7; return

h(x)}; (function (){ var x = 10; g(f); })() })() })() })()

Page 4: Control

Topics

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

Discussion of functional programming• Relevant to Haskell, section 4.4 of text

Page 5: Control

Fortran Control Structure

10 IF (X .GT. 0.000001) GO TO 2011 X = -X IF (X .LT. 0.000001) GO TO 5020 IF (X*Y .LT. 0.00001) GO TO 30 X = X-Y-Y30 X = X+Y ...50 CONTINUE X = A Y = B-A GO TO 11 …

Similar structure may occur in assembly code

Page 6: Control

Historical Debate

Dijkstra, Go To Statement Considered Harmful• Letter to Editor, C ACM, March 1968• Link on CS242 web site

Knuth, Structured Prog. with go to Statements• You can use goto, but do so in structured way …

Continued discussion• Welch, “GOTO (Considered Harmful)n, n is Odd”

General questions• Do syntactic rules force good programming style?• Can they help?

Page 7: Control

Advance in Computer Science

Standard constructs that structure jumpsif … then … else … endwhile … do … endfor … { … }case …

Modern style• Group code in logical blocks • Avoid explicit jumps except for function return• Cannot jump into middle of block or function

body

Page 8: Control

Exceptions: Structured Exit

Terminate part of computation • Jump out of construct• Pass data as part of jump• Return to most recent site set up to handle

exception• Unnecessary activation records may be deallocated

– May need to free heap space, other resources

Two main language constructs• Declaration to establish exception handler • Statement or expression to raise or throw exception

Often used for unusual or exceptional condition; other uses too

Page 9: Control

JavaScript Exceptions

throw e //jump to catch, passing exception object as parameter

try { … //code to try

} catch (e if e == …) { … //catch if first condition true

} catch (e if e == …) { … //catch if second condition true

} catch (e if e == …) { … //catch if third condition true

} catch (e){ … // catch any exception

} finally { … //code to execute after everything else

}

http://developer.mozilla.org/En/Core_JavaScript_1.5_Guide/ Exception_Handling_Statements

Page 10: Control

JavaScript Example

function invert(matrix) { if … throw “Determinant”;…

};

try { … invert(myMatrix); …}catch (e) { …

// recover from error}

Page 11: Control

ML Example (book discusses ML)

exception Determinant; (* declare exception name *)

fun invert (M) = (* function to invert matrix *) … if … then raise Determinant (* exit if Det=0 *) else … end;...invert (myMatrix) handle Determinant => … ;

Value for expression if determinant of myMatrix is 0

try catch

Page 12: Control

C++ Example

Matrix invert(Matrix m) { if … throw Determinant;…

};

try { … invert(myMatrix); …}catch (Determinant) { …

// recover from error}

Page 13: Control

ML Exceptions (cover briefly so book is useful to you)

Declarationexception name of type

gives name of exception and type of data passed when raised

Raise raise name parameters

expression form to raise and exception and pass data

Handlerexp1 handle pattern => exp2

evaluate first expressionif exception that matches pattern is raised, then evaluate second expression instead

General form allows multiple patterns.

Page 14: Control

C++ vs ML Exceptions

C++ exceptions• Can throw any type• Stroustrup: “I prefer to define types with no other purpose

than exception handling. This minimizes confusion about their purpose. In particular, I never use a built-in type, such as int, as an exception.” -- The C++ Programming Language, 3rd ed.

ML exceptions• Exceptions are a different kind of entity than types.• Declare exceptions before use

Similar, but ML requires the recommended C++ style.

Page 15: Control

Which handler is used?

Dynamic scoping of handlers• First call handles exception one way• Second call handles exception another• General dynamic scoping rule

Jump to most recently established handler on run-time stack

Dynamic scoping is not an accident• User knows how to handler error• Author of library function does not

exception Ovflw;

fun reciprocal(x) =

if x<min then raise Ovflw else 1/x;

(reciprocal(x) handle Ovflw=>0) / (reciprocal(y) handle Ovflw=>1);

try trycatch catch

throw

Page 16: Control

Exception for Error Condition

- datatype ‘a tree = LF of ‘a | ND of (‘a tree)*(‘a tree)

- exception No_Subtree;- fun lsub (LF x) = raise No_Subtree | lsub (ND(x,y)) = x;> val lsub = fn : ‘a tree -> ‘a tree

• This function raises an exception when there is no reasonable value to return

• We’ll look at typing later.

Page 17: Control

Exception for Efficiency

Function to multiply values of tree leavesfun prod(LF x) = x| prod(ND(x,y)) = prod(x) * prod(y);

Optimize using exceptionfun prod(tree) = let exception Zero fun p(LF x) = if x=0 then (raise Zero) else x | p(ND(x,y)) = p(x) * p(y) in p(tree) handle Zero=>0 end;

Page 18: Control

Dynamic Scope of Handler

exception X;(let fun f(y) = raise X and g(h) = h(1) handle X => 2in g(f) handle X => 4end) handle X => 6;

scope

handler

Which handler is used?

See JavaScript next slide

Page 19: Control

Dynamic Scope of Handler

try{ function f(y) { throw “exn”}; function g(h){ try {h(1)} catch(e){return

2} }; try { g(f) } catch(e){4};} catch(e){6};

Which catch catches the throw?

Page 20: Control

Dynamic Scope of Handler

try{ function f(y) { throw “exn”}; function g(h){ try {h(1)} catch(e){return 2} }; try { g(f) } catch(e){4};} catch(e){6};

catch(e) 6

formal hcatch(e) 2

access link

formal y 1access link

g(f)

f(1)

fun f access link

access link fun g

Dynamic scope: find first handler, going up the dynamic call chain

catch(e) 4access link

JavaScript version

Page 21: Control

Dynamic Scope of Handler

exception X;(let fun f(y) = raise X and g(h) = h(1) handle X

=> 2in g(f) handle X => 4end) handle X => 6;

handler X 6

formal hhandler X 2

access link

formal y 1access link

g(f)

f(1)

fun f access link

access link fun g

Dynamic scope: find first X handler, going up the dynamic call chain leading to raise X.

handler X 4access link

Book version (ML)

Page 22: Control

Compare to static scope of variables

exception X;(let fun f(y) = raise X and g(h) = h(1) handle X => 2in g(f) handle X => 4end) handle X => 6;

val x=6;(let fun f(y) = x and g(h) = let val x=2

in h(1) in let val x=4 in g(f) end);

Book version (ML)

Page 23: Control

Compare to static scope of variables

try{ function f(y) { throw “exn”}; function g(h){ try {h(1)} catch(e){return 2} }; try { g(f) } catch(e){4};} catch(e){6};

var x=6; function f(y) { return x}; function g(h){ var x=2; return h(1) }; (function (y) { var x=4; g(f) })(0);

JavaScript version

declaration

declaration

Page 24: Control

Static Scope of Declarations

var x=6;function f(y) { return x};function g(h){ var x=2; return h(1) }; (function (y) { var x=4; g(f) })(0);

var x 6

formal hvar x 2

access link

formal y 1access link

g(f)

f(1)

function f access link

access link function g

Static scope: find first x, following access links from the reference to X.

var x 4access link

JavaScript version

Page 25: Control

Static Scope of Declarations

val x=6;(let fun f(y) = x and g(h) = let val x=2 in h(1) in let val x=4 in g(f) end);

val x 6

formal hval x 2

access link

formal y 1access link

g(f)

f(1)

fun f access link

access link fun g

Static scope: find first x, following access links from the reference to X.

val x 4access link

Book version (ML)

Page 26: Control

Typing of Exceptions

Typing of raise exn• Recall definition of typing

– Expression e has type t if normal termination of e produces value of type t

• Raising exception is not normal termination– Example: 1 + raise X

Typing of handle exn => value• Converts exception to normal termination• Need type agreement• Examples

– 1 + ((raise X) handle X => e) Type of e must be int

– 1 + (e1 handle X => e2) Type of e1, e2 must be int

Page 27: Control

Exceptions and Resource Allocation

exception X;(let val x = ref [1,2,3] in let val y = ref

[4,5,6] in … raise X endend); handle X => ...

Resources may be allocated between handler and raise

May be “garbage” after exception

Examples• Memory• Lock on database• Threads• …

General problem: no obvious solution

Page 28: Control

Continuations

Idea:• The continuation of an expression is “the remaining

work to be done after evaluating the expression”• Continuation of 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 site design, other applications

Page 29: Control

Example of Continuation Concept

Expression • 2*x + 3*y + 1/x + 2/y

What is continuation of 1/x?• Remaining computation after division

var before = 2*x + 3*y; function cont(d) {return (before + d +

2/y)}; cont (1/x);

JavaScript version

Page 30: Control

Example of Continuation Concept

Expression • 2*x + 3*y + 1/x + 2/y

What is continuation of 1/x?• Remaining computation after division

let val before = 2*x + 3*y fun continue(d) = before + d + 2/y in continue (1/x) end

Book version (ML)

Page 31: Control

Example: Tail Recursive Factorial

Standard recursive functionfact(n) = if n=0 then 1 else n*fact(n-1)

Tail recursivef(n,k) = if n=0 then k else f(n-1, n*k)fact(n) = f(n,1)

How could we derive this?• Transform to continuation-passing form• Optimize continuation functions to single

integer

Page 32: Control

Continuation view of factorial

fact(n) = if n=0 then 1 else n*fact(n-1)

fact(9)

fact(8)

fact(7)

• This invocation multiplies by 9 and returns

• Continuation of fact(8) is x. 9*x

• Multiplies by 8 and returns• Continuation of fact(7) is y. (x. 9*x) (8*y)

• Multiplies by 7 and returns• Continuation of fact(6) is z. (y. (x. 9*x) (8*y)) (7*z)

return

n 9

...

return

n 8

...

return

n 7

...

Page 33: Control

Derivation of tail recursive form

Standard functionfact(n) = if n=0 then 1 else n*fact(n-1)

Continuation formfact(n, k) = if n=0 then k(1) else fact(n-1, x.k (n*x) )

fact(n, x.x) computes n!

Example computation

fact(3,x.x) = fact(2, y.((x.x) (3*y)))

= fact(1, x.((y.3*y)(2*x)))

= x.((y.3*y)(2*x)) 1 = 6

continuation

Page 34: Control

Tail Recursive Form

Optimization of continuationsfact(n,a) = if n=0 then a else fact(n-1, n*a )

Each continuation is effectively x.(a*x) for some a

Example computation

fact(3,1) = fact(2, 3) was fact(2, y.3*y)

= fact(1, 6) was fact(1, x.6*x)

= 6

Page 35: Control

Other uses for continuations

Explicit control• Normal termination -- call continuation• Abnormal termination -- do something else

Compilation techniques• Call to continuation is functional form of “go to”• Continuation-passing style makes control flow

explicit

MacQueen: “Callcc is the closest thing to a

‘come-from’ statement I’ve ever seen.”

Page 36: Control

Theme Song: Charlie on the MTA

Let me tell you the story Of a man named Charlie On a tragic and fateful day He put ten cents in his pocket, Kissed his wife and family Went to ride on the MTA

Charlie handed in his dime At the Kendall Square Station And he changed for Jamaica Plain When he got there the conductor told him, "One more nickel." Charlie could not get off that train.

Chorus:                         Did he ever return,                         No he never returned                         And his fate is still unlearn'd                         He may ride forever                         'neath the streets of Boston                         He's the man who never returned.

Page 37: Control

Capturing Current Continuation

Language feature (use open SMLofNJ; on Leland)

• callcc : call a function with current continuation • Can be used to abort subcomputation and go on

Examples• callcc (fn k => 1);> val it = 1 : int

– Current continuation is “fn x => print x”– Continuation is not used in expression

• 1 + callcc(fn k => 5 + throw k 2);> val it = 3 : int

– Current continuation is “fn x => print 1+x”– Subexpression throw k 2 applies continuation to 2

skip callcc, at least for now

Page 38: Control

More with callcc

Example1 + callcc(fn k1=> … callcc(fn k2 => … if … then (throw k1 0) else (throw k2 “stuck”) ))

Intuition• Callcc lets you mark a point in program that you can

return to• Throw lets you jump to that point and continue from

there

Page 39: Control

Example

Pass two continuations and choose onefun f(x,k1,k2) = 3 + (if x>0 then throw k1(x) else throw k2(x));fun g(y,k1) = 2 + callcc(fn k2 => f(y,k1,k2));fun h(z) = 1 + callcc(fn k1 => g(z+1,k1));

h(1);h(~2);

Answers: h(1) 3 h(~2) 2

Page 40: Control

Continuations in Mach OS

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– Sys call such as msg_recv can block– Kernel code calls msg_recv with continuation passed as

arg

• Advantage/Disadvantage– Saves a lot of space, need to write “continuation”

functions

Page 41: Control

“Continuations” in Web programming

XMLHttpRequest similar to callcc:function callcc(url) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.send(null); return xhr.responseText;}

Usage: alert(callcc('http://a.com/describe?id=10'));

Server invokes continuation by sending a response Unfortunately, this pauses client while server runs

Page 42: Control

“Continuations” in Web programming

Asynchronous XHR also similar to continuations:function callWithContinuation(url, k) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onreadystatechange = function () { if (xhr.readyState == 4) k(xhr.responseText); } xhr.send(null);}

Usage: callWithContinuation('http://a.com/describe?id=10', alert);

Client continues while server runs Basis of AJAX Web programming paradigm

Page 43: Control

Continuations in compilation

SML continuation-based compiler [Appel, Steele]1) Lexical analysis, parsing, type checking2) Translation to -calculus form3) Conversion to continuation-passing style (CPS)4) Optimization of CPS5) Closure conversion – eliminate free variables6) Elimination of nested scopes7) Register spilling – no expression with >n free vars8) Generation of target assembly language program9) Assembly to produce target-machine program

Page 44: Control

Coroutines (this is complicated…)

datatype tree = leaf of int | node of tree*tree;

datatype coA = A of (int* coB) cont (* searchA wants int and B-cont*)and coB = B of coA cont; (* searchB wants an A-continuation

*)

fun resumeA(x, A k) = callcc(fn k' => throw k (x, B k'));fun resumeB( B k) = callcc(fn k' => throw k (A k'));exception DISAGREE; exception DONE;

fun searchA(leaf(x),(y, other: coB)) = if x=y then resumeB(other) else raise DISAGREE| searchA(node(t1,t2), other) = searchA(t2, searchA(t1, other));

fun searchB(leaf(x), other : coA) = resumeA(x,other) | searchB(node(t1,t2), other) = searchB(t2, searchB(t1, other));

fun startB(t: tree) = callcc(fn k => (searchB(t, A k); raise DONE)); fun compare(t1,t2) = searchA(t1, startB(t2));

skip callcc, at least for now

Page 45: Control

Summary

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 application development, …

Page 46: Control

What is a functional language ?

“No side effects” OK, we have side effects, but we also have

higher-order functions…

We will use pure functional language to mean “a language with functions, but without side

effects or other imperative features.”

Page 47: Control

No-side-effects language test

Within the scope of specific declarations of x1,x2, …, xn, all occurrences of an expression e containing only variables x1,x2, …, xn, must have the same value.

Examplebegin

integer x=3; integer y=4; 5*(x+y)-3 … // no new declaration of x or y // 4*(x+y)+1end

?

Page 48: Control

Example languages

Pure Lispatom, eq, car, cdr, cons, lambda, define

Impure Lisp: rplaca, rplacd

lambda (x) (cons (car x) (… (rplaca (… x …) ...) ... (car x) … )))Cannot just evaluate (car x) once

Common procedural languages are not functional• Pascal, C, Ada, C++, Java, Modula, … Example functional programs in a couple of slides

Page 49: Control

Backus’ Turing Award

John Backus was designer of Fortran, BNF, etc.

Turing Award in 1977 Turing Award Lecture

• Functional prog better than imperative programming

• Easier to reason about functional programs• More efficient due to parallelism• Algebraic laws

Reason about programsOptimizing compilers

Page 50: Control

Reasoning about programs

To prove a program correct, • must consider everything a program depends on

In functional programs,• dependence on any data structure is explicit

Therefore, • easier to reason about functional programs

Do you believe this?• This thesis must be tested in practice• Many who prove properties of programs believe this• Not many people really prove their code correct

Page 51: Control

Haskell Quicksort

Very succinct programqsort [] = [] qsort (x:xs) = qsort elts_lt_x ++ [x] ++ qsort elts_greq_x

where elts_lt_x = [y | y <- xs, y < x] elts_greq_x = [y | y <- xs, y >= x]

This is the whole thing• No assignment – just write expression for

sorted list• No array indices, no pointers, no memory

management, …

Page 52: Control

Compare: C quicksort

qsort( a, lo, hi ) int a[], hi, lo; { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); t = a[l]; a[l] = a[hi]; a[hi] = t; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } }

Page 53: Control

Interesting case study

Naval Center programming experiment• Separate teams worked on separate languages• Surprising differences

Some programs were incomplete or did not run• Many evaluators didn’t understand, when shown the

code, that the Haskell program was complete. They thought it was a high level partial specification.

Hudak and Jones, Haskell vs Ada vs C++ vs Awk vs …,Yale University Tech Report, 1994

Page 54: Control

Disadvantages of Functional Prog

Functional programs often less efficient. Why?

Change 3rd element of list x to y(cons (car x) (cons (cadr x) (cons y (cdddr x))))

– Build new cells for first three elements of list(rplaca (cddr x) y)

– Change contents of third cell of list directly

However, many optimizations are possible

A B C D

Page 55: Control

Von Neumann bottleneck

Von Neumann• Mathematician responsible for idea of stored

program

Von Neumann Bottleneck• Backus’ term for limitation in CPU-memory transfer

Related to sequentiality of imperative languages• Code must be executed in specific order

function f(x) { if (x<y) then y = x; else x = y; }g( f(i), f(j) );

Page 56: Control

Eliminating VN Bottleneck

No side effects• Evaluate subexpressions independently• Example

– function f(x) { return x<y ? 1 : 2; }– g(f(i), f(j), f(k), … );

Does this work in practice? Good idea but ...• Too much parallelism• Little help in allocation of processors to processes• ... • David Shaw promised to build the non-Von ...

Effective, easy concurrency is a hard problem