Anda di halaman 1dari 261

Tutorial Sessions:

Concepts-Based Teaching
of Programming
Oct. 10-11, 2005
Peter Van Roy
Universit catholique de Louvain
Louvain-la-Neuve, Belgium
Invited tutorials, CIESC 2005

10/10/2005

P. Van Roy, CIESC tutorials

Teaching with concepts

Instead of teaching programming languages, we teach


programming concepts!
With the multiparadigm language Oz it is possible to teach
many concepts, covering many paradigms
Let us first see some of the course organizations

Then we will give a number of sample lectures, each in detail


with hands-on examples

From second-year to graduate courses

These were selected to give a variety of different concepts

We will not talk about logic programming in these tutorials, for


lack of time

10/10/2005

Although it is an important topic!


P. Van Roy, CIESC tutorials

Overview of the tutorial

Examples of some course organizations


Mozart Programming System
Example lessons

The bulk of the tutorial will be a carefully selected


set of real lectures
You and I together will run the code in the
lectures using the Mozart system

Conclusions

10/10/2005

P. Van Roy, CIESC tutorials

Mozart
Programming System

10/10/2005

P. Van Roy, CIESC tutorials

Mozart Programming System

All the lectures are designed to be accompanied by the


Mozart Programming System
Mozart is a program development platform that implements
the Oz language
Mozart has an interactive interface based on emacs

Mozart is a high-quality implementation that can execute all


the example programs in the book

Windows junkies tend not to like emacs, which comes from a


Unix background

Mozart is the product of more than a decade of research and


implementation by an international group
Mozart is released under an Open Source license

See http://www.mozart-oz.org for more information and


downloads

10/10/2005

P. Van Roy, CIESC tutorials

Some Course
Organizations

10/10/2005

P. Van Roy, CIESC tutorials

Some courses (1)

Second-year course (Datalogi II at KTH,


CS2104 at NUS) by Seif Haridi and
Christian Schulte

Start with declarative programming


Explain declarative techniques and
higher-order programming
Explain semantics
Add threads: leads to declarative
(dataflow) concurrency
Add ports (communication channels):
leads to message-passing concurrency
(agents)

Declarative programming, concurrency,


and multi-agent systems

10/10/2005

Declarative
programming
+ threads
Declarative
concurrency
+ ports
Message-passing
concurrency

For many reasons, this is a better start


than OOP

P. Van Roy, CIESC tutorials

Some courses (2)

Second-year course (FSAC1450,


LINF1251, FSAB1402 at UCL) by
Peter Van Roy

Start with declarative programming


Explain declarative techniques
Explain semantics
Add cells (mutable state)
Explain data abstraction: objects and
ADTs
Explain object-oriented programming:
classes, polymorphism, and
inheritance
Add threads: leads to declarative
concurrency

Declarative
programming

+ cells
Stateful
programming and
data abstraction

+ threads
Declarative
concurrency
and agents

Most comprehensive overview in one


early course

10/10/2005

P. Van Roy, CIESC tutorials

Some courses (3)

Third-year course (INGI2131 at


UCL) by Peter Van Roy

Designing multi-agent systems

Add cells (mutable state): leads to


shared-state concurrency

+ threads

Add by-need synchronization:


leads to lazy execution
Combining lazy execution and
concurrency

Declarative
concurrency

Add ports (communication channels):


leads to message-passing
concurrency

Declarative
programming

Review of declarative programming


Add threads: leads to declarative
concurrency

+ ports
Message-passing
concurrency

+ by-need

Lazy
evaluation

+ cells
Shared-state
concurrency

Tuple spaces (Linda-like)


Locks, monitors, transactions

Focus on concurrent programming


10/10/2005

P. Van Roy, CIESC tutorials

A more advanced course (4)


Declarative
programming

+ cells
Stateful
programming

+ classes
Object-oriented
programming

+ threads
Shared-state
concurrency

+ threads
Declarative
concurrency

+ by-need
Lazy
evaluation

+ search
Relational
programming

+ ports
Message-passing
concurrency

+ constraints
Constraint
programming

This is an example of a more advanced course given at an unnamed institution


It covers many more paradigms, their semantics, and some of their relationships
It can be given as a graduate course

10/10/2005

P. Van Roy, CIESC tutorials

10

Example Lectures

10/10/2005

P. Van Roy, CIESC tutorials

11

Example lectures

Lesson 1: Hands-on Introduction to Programming Concepts


Lesson 2: Language Syntax
Lesson 3: Introduction to Language Semantics
Lesson 4: Declarative Programming
Lesson 5: Stateful Programming
Lesson 6: Language Semantics with an Abstract Machine
Lesson 7: Executing the Abstract Machine
Lesson 8: Declarative Concurrency
Lesson 9: Object-Oriented Programming
Conclusions: These lessons only scratch the surface

10/10/2005

See the full courses for complete and pedagogical sets of


concepts
P. Van Roy, CIESC tutorials

12

Lectures in French

There is another set of course slides in French


The French slides are the most recent ones

I am teaching a second-year course in Fall 2005, namely


FSAB1402, to 350 engineering students

See http://www.info.ucl.ac.be/notes_de_cours/FSAB1402/
See also http://www.info.ucl.ac.be/people/PVR/coursfrancais.html

FSAB1402 covers a lot of ground


My CIESC tutorials are not based on the French slides but on the
English slides given in the courses CS2104 (NUS), DatalogiII
(KTH), and LINF1251 (UCL) by Seif Haridi, Christian Schulte,
and Peter Van Roy
But I recommend you take a look at the French slides!

10/10/2005

P. Van Roy, CIESC tutorials

13

The Textbook

10/10/2005

P. Van Roy, CIESC tutorials

14

The textbook

We have written a textbook to support the


concepts-based approach

Goals of the textbook

Concepts, Techniques, and Models of


Computer Programming, MIT Press, 2004, 929
pages
The textbook is based on more than a decade of
research by an international group, the Mozart
Consortium
To present programming as a unified discipline
in which each programming paradigm has its
part
To teach programming without the limitations of
particular languages and their historical
accidents of syntax and semantics

All the examples and courses we will give are


part of the textbook

10/10/2005

A single 2-semester-hour course covers about


1/3 of the book
P. Van Roy, CIESC tutorials

15

Lesson 1:
Hands-on Introduction
to Programming Concepts

10/10/2005

P. Van Roy, CIESC tutorials

16

Lesson 1

Hands-on introduction to programming


concepts
This is one way to get the class used to the
environment and also to introduce
programming concepts, to give the students
some intuitions to start the course

10/10/2005

P. Van Roy, CIESC tutorials

17

Overview of programming
concepts

Simple calculator
Declarative variables
Functions
Structured data (example: lists)
Functions over lists
Correctness and complexity
Lazy functions
Concurrency and dataflow
State, objects, and classes
Nondeterminism and atomicity

10/10/2005

P. Van Roy, CIESC tutorials

18

A calculator

Use the Mozart system as a


calculator

{Browse 9999*9999}

10/10/2005

P. Van Roy, CIESC tutorials

19

Variables

Variables are short-cuts for values, they cannot be assigned


more than once
declare
V = 9999*9999
{Browse V*V}

Variable identifier is what you type


Variable in memory (store variable) is what is used in the
calculation
The declare statement creates a store variable and assigns
its memory address to the identifier V in the environmen

10/10/2005

P. Van Roy, CIESC tutorials

20

Functions

Compute the factorial function:


Start with the mathematical definition
declare
n!= 1 2 L (n 1) n
fun {Fact N}
if N==0 then 1 else N*{Fact N-1} end 0!= 1
end
n!= n (n 1)! if n > 0

Fact is declared in the environment


Try large factorial {Browse {Fact 100}}

10/10/2005

P. Van Roy, CIESC tutorials

21

Composing functions
Combinations of r items taken from n.
The number of subsets of size r taken from a set of size n
n
n!
Comb
=

r r!(n r )!

declare
fun {Comb N R}
{Fact N} div ({Fact R}*{Fact N-R})
end

Fact

Fact

Fact

Example of functional abstraction

10/10/2005

P. Van Roy, CIESC tutorials

22

Structured data (lists)

Calculate Pascal triangle


Write a function that calculates the nth
row as one structured value
A list is a sequence of elements:
[1 4 6 4 1]
The empty list is written nil
Lists are created by means of | (cons)

1
1
1
1
1

1
2

3
4

1
3

1
4

declare
H=1
T = [2 3 4 5]
{Browse H|T} % Shows [1 2 3 4 5]
10/10/2005

P. Van Roy, CIESC tutorials

23

More on lists

Taking lists apart (selecting components)


A cons has two components a head, and tail
declare L = [5 6 7 8] |
L.1 gives 5
6
|
L.2 give [6 7 8]
|

7
8
10/10/2005

P. Van Roy, CIESC tutorials

nil
24

Pattern matching

Another way to take a list apart is by use of


pattern matching with a case instruction
case L of H|T then
{Browse H} {Browse T}
end

10/10/2005

P. Van Roy, CIESC tutorials

25

Functions over lists (1)


1

1.
2.
3.

Compute the function


{Pascal N}
Takes an integer N, and
returns the Nth row of a
Pascal triangle as a list
For row 1, the result is [1]
For row N, shift to left row N-1
and shift to the right row N-1
Align and add the shifted rows
element-wise to get row N

10/10/2005

P. Van Roy, CIESC tutorials

1
1
(0) 1
1

1
2

3
4

1
3

1 (0)
4

Shift right [0 1 3 3 1]
Shift left [1 3 3 1 0]
26

Functions over lists (2)


Pascal N
declare
fun {Pascal N}
if N==1 then [1]
else
{AddList
{ShiftLeft {Pascal N-1}}
{ShiftRight {Pascal N-1}}}
end
end

10/10/2005

Pascal N-1

Pascal N-1

ShiftLeft

ShiftRight

P. Van Roy, CIESC tutorials

AddList

27

Functions over lists (3)


fun {ShiftLeft L}
case L of H|T then
H|{ShiftLeft T}
else [0]
end
end

fun {AddList L1 L2}


case L1 of H1|T1 then
case L2 of H2|T2 then
H1+H2|{AddList T1 T2}
end
else nil end
end

fun {ShiftRight L} 0|L end

10/10/2005

P. Van Roy, CIESC tutorials

28

Top-down program
development

Understand how to solve the problem by hand


Try to solve the task by decomposing it to simpler
tasks
Devise the main function (main task) in terms of
suitable auxiliary functions (subtasks) that
simplifies the solution (ShiftLeft, ShiftRight, and
AddList)
Complete the solution by writing the auxiliary
functions

10/10/2005

P. Van Roy, CIESC tutorials

29

Is your program correct?

A program is correct when it does what we would


like it to do
In general we need to reason about the program:
Semantics of the language: a precise model of the
operations of the programming language
Program specification: a definition of the output in
terms of the input (usually a mathematical function
or relation)
Use mathematical techniques to reason about the
program, using programming language semantics

10/10/2005

P. Van Roy, CIESC tutorials

30

Mathematical induction

Select one or more input to the function


Show the program is correct for the simple cases
(base case)
Show that if the program is correct for a given case,
it is then correct for the next case.
For integers base case is either 0 or 1, and for any
integer n the next case is n+1
For lists the base case is nil, or a list with one or few
elements, and for any list T the next case H|T

10/10/2005

P. Van Roy, CIESC tutorials

31

Correctness of factorial
fun {Fact N}
if N==0 then 1 else N*{Fact N-1} end
end

Base Case: {Fact 0} returns 1


Inductive Case: (N>1), N*{Fact N-1} assume {Fact
N-1} is correct, from the spec we see that {Fact N} is
N*{Fact N-1}
More techniques to come!

10/10/2005

P. Van Roy, CIESC tutorials

32

Complexity

Pascal runs very slow,


try {Pascal 24}
{Pascal 20} calls: {Pascal 19} twice,
{Pascal 18} four times, {Pascal 17}
eight times, ..., {Pascal 1} 219 times
Execution time of a program up to a
constant factor is called programs
time complexity.
Time complexity of {Pascal N} is
proportional to 2N (exponential)
Programs with exponential time
complexity are impractical
10/10/2005

P. Van Roy, CIESC tutorials

declare
fun {Pascal N}
if N==1 then [1]
else
{AddList
{ShiftLeft {Pascal N-1}}
{ShiftRight {Pascal N-1}}}
end
end

33

Faster Pascal

Introduce a local variable L


Compute {FastPascal N-1}
only once
Try with 30 rows.
FastPascal is called N times,
each time a list on the average
of size N/2 is processed
The time complexity is
proportional to N2 (polynomial)
Low order polynomial
programs are practical.

10/10/2005

fun {FastPascal N}
if N==1 then [1]
else
local L in
L={FastPascal N-1}
{AddList {ShiftLeft L}
{ShiftRight L}}
end
end
end

P. Van Roy, CIESC tutorials

34

Lazy evaluation (1)

The functions written so far are evaluated eagerly


(as soon as they are called)
Another way is lazy evaluation where a computation
is done only when the results is needed
Calculates the infinite list:
0 | 1 | 2 | 3 | ...

10/10/2005

P. Van Roy, CIESC tutorials

declare
fun lazy {Ints N}
N|{Ints N+1}
end

35

Lazy evaluation (2)

Write a function that


computes as many rows of
Pascals triangle as needed
We do not know how many
beforehand
A function is lazy if it is
evaluated only when its result
is needed
The function PascalList is
evaluated when needed
10/10/2005

fun lazy {PascalList Row}


Row | {PascalList
{AddList
{ShiftLeft Row}
{ShiftRight Row}}}
end

P. Van Roy, CIESC tutorials

36

Lazy evaluation (3)

Lazy evaluation will


avoid redoing work if
you decide first you
need the 10th row and
later the 11th row
The function continues
where it left off

10/10/2005

declare
L = {PascalList [1]}
{Browse L}
{Browse L.1}
{Browse L.2.1}

L<Future>
[1]
[1 1]

P. Van Roy, CIESC tutorials

37

Higher-order programming

Assume we want to write another Pascal function which


instead of adding numbers performs exclusive-or on them
It calculates for each number whether it is odd or even (parity)
Either write a new function each time we need a new
operation, or write one generic function that takes an
operation (another function) as argument
The ability to pass functions as argument, or return a function
as result is called higher-order programming
Higher-order programming is an aid to build generic
abstractions

10/10/2005

P. Van Roy, CIESC tutorials

38

Variations of Pascal

Compute the parity Pascal triangle


fun {Xor X Y} if X==Y then 0 else 1 end end
1
1
1
1
1

10/10/2005

1
2

3
4

1
1
1
3

1
1

1
1

P. Van Roy, CIESC tutorials

1
0

1
0

1
1

1
0

39

Higher-order programming
fun {GenericPascal Op N}
if N==1 then [1]
else L in L = {GenericPascal Op N-1}
{OpList Op {ShiftLeft L} {ShiftRight L}}
end
end
fun {OpList Op L1 L2}
case L1 of H1|T1 then
case L2 of H2|T2 then
{Op H1 H2}|{OpList Op T1 T2}
end
end
else nil end
end

10/10/2005

fun {Add N1 N2} N1+N2 end


fun {Xor N1 N2}
if N1==N2 then 0 else 1 end
end
fun {Pascal N} {GenericPascal Add N}
end
fun {ParityPascal N}
{GenericPascal Xor N}
end

P. Van Roy, CIESC tutorials

40

Concurrency

How to do several things at once


Concurrency: running several
activities each running at its own
pace
A thread is an executing sequential
program
A program can have multiple
threads by using the thread
instruction
{Browse 99*99} can immediately
respond while Pascal is computing

10/10/2005

P. Van Roy, CIESC tutorials

thread
P in
P = {Pascal 21}
{Browse P}
end
{Browse 99*99}

41

Dataflow (1)

What happens when multiple threads


try to communicate?
A simple way is to make
communicating threads synchronize on
the availability of data (data-driven
execution)
If an operation tries to use a variable
that is not yet bound it will wait
The variable is called a dataflow
variable

10/10/2005

P. Van Roy, CIESC tutorials

42

Dataflow (2)

Two important properties of


dataflow

Calculations work correctly


independent of how they are
partitioned between threads
(concurrent activities)
Calculations are patient, they do
not signal error; they wait for
data availability

The dataflow property of


variables makes sense when
programs are composed of
multiple threads

10/10/2005

P. Van Roy, CIESC tutorials

declare X
thread
{Delay 5000} X=99
end
{Browse Start}
{Browse X*X}
declare X
thread
{Browse Start}
{Browse X*X}
end
{Delay 5000} X=99
43

State

How to make a function learn from its past?


We would like to add memory to a function to
remember past results
Adding memory as well as concurrency is an
essential aspect of modeling the real world
Consider {FastPascal N}: we would like it to
remember the previous rows it calculated in
order to avoid recalculating them
We need a concept (a memory cell) to store,
change and retrieve a value
The simplest concept is a (memory) cell which
is a container of a value
One can create a cell, assign a value to a cell,
and access the current value of the cell
Cells are not variables!

10/10/2005

P. Van Roy, CIESC tutorials

declare
C = {NewCell 0}
C:= @C + 1
{Browse @C}

44

Example of state

Add memory to
Pascal to remember
how many times it is
called
The memory (state)
is global here
Memory that is local
to a function is called
encapsulated state

10/10/2005

declare
C = {NewCell 0}
fun {FastPascal N}
C:=@C+1
{GenericPascal Add N}
end

P. Van Roy, CIESC tutorials

45

Objects

Functions with internal


memory are called objects
The cell is invisible outside of
the definition

declare
fun {FastPascal N}
{Browse {Bump}}
{GenericPascal Add N}
end

10/10/2005

declare
local C in
C = {NewCell 0}
fun {Bump}
C:=@C+1
@C
end
end

P. Van Roy, CIESC tutorials

46

Classes (1)

A class is a factory
of objects where
each object has its
own internal state
Let us create many
independent counter
objects with the
same behavior

10/10/2005

fun {NewCounter}
local C Bump in
C = {NewCell 0}
fun {Bump}
C:=@C+1
@C
end
Bump
end
end

P. Van Roy, CIESC tutorials

47

Classes (2)

Here is a class with


two operations:
Bump and Read

10/10/2005

fun {NewCounter}
local C Bump in
C = {NewCell 0}
fun {Bump}
C:=@C+1
@C
end
fun {Read}
@C
end
[Bump Read]
end
end

P. Van Roy, CIESC tutorials

48

Object-oriented programming

In object-oriented programming the idea of


objects and classes is pushed farther
Classes keep the basic properties of:

State encapsulation
Object factories

Classes are extended with more sophisticated


properties:

10/10/2005

They have multiple operations (called methods)


Methods can be called by their names (giving
polymorphism)
They can be defined by taking another class and
extending it slightly (inheritance)
P. Van Roy, CIESC tutorials

49

Nondeterminism (1)

What happens if a program has both


concurrency and state together?
This is very tricky
The same program can give different
results from one execution to the next
This variability is called nondeterminism
Internal nondeterminism is not a problem if
it is not observable from outside

10/10/2005

P. Van Roy, CIESC tutorials

50

Nondeterminism (2)
declare
C = {NewCell 0}
thread C:=1 end
thread C:=2 end

t0

C = {NewCell 0}
cell C contains 0

t1

C:=1
cell C contains 1

t2

C:=2
cell C contains 2 (final value)

time
10/10/2005

P. Van Roy, CIESC tutorials

51

Nondeterminism (3)
declare
C = {NewCell 0}
thread C:=1 end
thread C:=2 end

t0

C = {NewCell 0}
cell C contains 0

t1

C:=2
cell C contains 2

t2

C:=1
cell C contains 1 (final value)

time
10/10/2005

P. Van Roy, CIESC tutorials

52

Nondeterminism (4)
declare
C = {NewCell 0}

thread I in
I = @C
C:= I+1
end
thread J in
J = @C
C:= J+1
end

10/10/2005

What are the possible


results?
Both threads
increment the cell C
by 1
Expected final result
of C is 2
Is that all?

P. Van Roy, CIESC tutorials

53

Nondeterminism (5)

Another possible final result is the


t0
cell C containing the value 1
declare
C = {NewCell 0}
thread I in
I = @C
C:= I+1
end
thread J in
J = @C
C:= J+1
end

10/10/2005

C = {NewCell 0}

t1

I = @C

t2

J = @C

I equal 0
J equal 0

t3

C:= J+1

t4

C:= I+1

C contains 1
C contains 1
time

P. Van Roy, CIESC tutorials

54

Insights gained

1.
2.
3.

Combining concurrency and state is tricky


Complex programs have many possible interleavings
Programming is a question of mastering the interleavings
Famous bugs in the history of computer technology are due
to designers overlooking an interleaving (e.g., the Therac-25
radiation therapy machine giving doses 1000s of times too
high, resulting in death or injury)
If possible try to avoid concurrency and state together
Encapsulate state and communicate between threads using
dataflow
Try to master interleavings by using atomic operations

10/10/2005

P. Van Roy, CIESC tutorials

55

Atomicity (1)

How can we master the interleavings?


One idea is to reduce the number of interleavings
by programming with coarse-grained atomic
operations
An operation is atomic if it is performed as a
whole or nothing
No intermediate (partial) results can be observed
by any other concurrent activity
In simple cases we can use a lock to ensure
atomicity of a sequence of operations
For this we need a new entity (a lock)

10/10/2005

P. Van Roy, CIESC tutorials

56

Atomicity (2)
declare
L = {NewLock}
lock L then
sequence of ops 1

end

10/10/2005

Thread 1

lock L then
sequence of ops 2
end

P. Van Roy, CIESC tutorials

Thread 2

57

Using atomicity
declare
C = {NewCell 0}
L = {NewLock}
thread
lock L then I in
I = @C
C:= I+1
end
end
thread
lock L then J in
J = @C
C:= J+1
end
end

10/10/2005

The final content of C is


always 2

P. Van Roy, CIESC tutorials

58

Lesson 2:
Language Syntax

10/10/2005

P. Van Roy, CIESC tutorials

59

Description of a language

Language = Syntax + Semantics


The syntax of a language is concerned with
the form of a program: how expressions,
commands, declarations etc. are put together
to result in the final program.
The semantics of a language is concerned
with the meaning of a program: how the
programs behave when executed on
computers.

10/10/2005

P. Van Roy, CIESC tutorials

60

Programming language definition

Syntax: grammatical structure

lexical
phrasal

how words are formed


how sentences are formed from words

Semantics: meaning of programs

Informal: English documents (e.g. Reference manuals,


language tutorials and FAQs etc.)
Formal:

10/10/2005

Operational Semantics (execution on an abstract machine)


Denotational Semantics (each construct defines a function)
Axiomatic Semantics (each construct is defined by pre and
post conditions)
P. Van Roy, CIESC tutorials

61

Language syntax (1)

Defines legal programs

Defined by grammar rules

programs that can be executed by machine


define how to make sentences out of words

For programming languages

10/10/2005

sentences are called statements (commands,


expressions)
words are called tokens
grammar rules describe both tokens and statements
P. Van Roy, CIESC tutorials

62

Language syntax (2)

Statement is sequence of tokens


Token is sequence of characters
Lexical analyzer is a program

Parser is a program

recognizes character sequence


produces token sequence
recognizes token sequence
produces statement representation

Statements are represented as


parse trees
10/10/2005

P. Van Roy, CIESC tutorials

characters

Lexical analyzer
tokens

Parser
sentences

63

Backus-Naur Form

BNF (Backus-Naur Form) is a common notation to define


grammars for programming languages
A BNF grammar is set of grammar (rewriting) rules
A set of terminal symbols (tokens)
A set of Non-terminal symbols
One start symbol
A grammar rule
nonterminal ::= sequence of terminal and nonterminal

10/10/2005

P. Van Roy, CIESC tutorials

64

Examples of BNF
(A) BNF rules for robot commands
A robot arm only accepts a command from
{up, down, left, right}
move ::= cmd
move ::= cmd move
cmd ::= up
cmd ::= down
cmd ::= left
cmd ::= right
10/10/2005

P. Van Roy, CIESC tutorials

65

Grammar rules

digit is defined to represent one of the ten


tokens 0, 1, , 9
digit ::= 0 | 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9

The symbol | is read as or


Another reading is that digit describes the
set of tokens {0,1,, 9}

10/10/2005

P. Van Roy, CIESC tutorials

66

Examples of BNF (1)


(A) BNF rules for robot commands
A robot arm only accepts a command from {up, down,
left, right}
move ::= cmd | cmd move
cmd ::= up | down | left | right

Examples of command sequences :

10/10/2005

up
down left
up down down up right left
P. Van Roy, CIESC tutorials

67

Examples of BNF (2)

Integers
integer ::= digit | digit integer
digit ::= 0 | 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9
integer is defined as the sequence of a digit
followed by zero or more digits

10/10/2005

P. Van Roy, CIESC tutorials

68

Extended Backus-Naur Form

EBNF (Extended Backus-Naur Form) is a


common notation to define grammars for
programming languages
Terminal symbols and non-terminal symbols
Terminal symbol is a token
Nonterminal symbol is a sequence of tokens,
and is represented by a grammar rule
nonterminal ::= rule body

10/10/2005

P. Van Roy, CIESC tutorials

69

Grammar rules

Grammar rules may refer to other


nonterminals
integer ::= digit { digit }
integer is defined as the sequence of a
digit followed by zero or more digits

10/10/2005

P. Van Roy, CIESC tutorials

70

Grammar rule constructs

x
x ::= Body
x | y
x y
{ x }

{ x }+

[ x ]

10/10/2005

nonterminal x
x is defined by Body
either x or y (choice)
the sequence x followed by y
sequence of zero or more
occurrences of x
sequence of one or more
occurrences of x
zero or one occurrence of x
P. Van Roy, CIESC tutorials

71

How to read grammar rules

From left to right

Gives the following sequence

10/10/2005

each terminal symbol is added to the sequence


each nonterminal is replaced by its definition
for each x | y pick any of the alternatives
for each x y is the sequence x followed by the
sequence y

P. Van Roy, CIESC tutorials

72

Examples

statement ::= skip | expression = expression |


expression ::= variable | integer |

statement ::= if expression then statement


{ elseif expression then statement }
[ else statement ] end |

10/10/2005

P. Van Roy, CIESC tutorials

73

Context-Free Grammars (1)

Grammar rules can be used to

verify that a statement is legal


generate all possible statements

The set of all possible statements generated from


a grammar and one nonterminal symbol is called a
(formal) language
EBNF notation defines essentially a class of
grammars called context-free grammars
Expansion of a nonterminal is always the same
regardless of where it is used

10/10/2005

P. Van Roy, CIESC tutorials

74

Context-Free Grammars (2)


Example 1:

Let = {a}, T = {0,1}


= {a ::= 11a0, a ::= 110}, = a
110 L(G)

111100 L(G)

But 011 L(G)

2nd rule

???

1st rule

110

11

0
011

2nd rule

110

These trees are called parse trees or


P. Van Roy, CIESC tutorials
syntax trees

10/10/2005

75

More examples of EBNF


(C) BNF rules for Real Numbers;
<real-#>
<int-part>
<fraction>
<digit>

::=
::=
::=
::=

<int-part> . <fraction>
<digit> | <int-part> <digit>
<digit> | <digit> <fraction>
0|1|2|3|4|5|6|7|8|9
<real-#>
<int-part>

<fraction>

<int-part>

<digit>

<digit>

<fraction>

<digit>

<digit>

1
10/10/2005

9
P. Van Roy, CIESC tutorials

76

Ambiguity (1)

A grammar is ambiguous if there exists a string


which gives rise to more than one parse tree.
Most common cause is due to infix binary operation

expr ::= num|expr-expr


Parse: 1-2-3

10/10/2005

P. Van Roy, CIESC tutorials

77

Ambiguity (2)
expr ::= num|expr-expr
Parse: (1-2)-3

expr

expr

expr

10/10/2005

expr

num

num

P. Van Roy, CIESC tutorials

expr

num

78

Ambiguity (3)
expr ::= num|expr-expr
Parse: 1-(2-3)
Which parse tree?

expr
expr

num

expr

expr

expr

num

num

10/10/2005

P. Van Roy, CIESC tutorials

79

Ambiguity resolution
for binary operators (1)

(A) Associative Rules


Given a binary operator op and a string
a1 op a2 op a3
Ifa1 op a2 op a3 is interpreted as (a1 op a2) op a3,
then op is left associative.

Ifa1 op a2 op a3 is interpreted as a1 op (a2 op a3),


then op is right associative.

It is possible that op is neither left nor right


associative. In which case a1 op a2 op a3 will be
treated as a syntax error.

10/10/2005

P. Van Roy, CIESC tutorials

80

Ambiguity resolution
for binary operators (2)

Example: We have seen that this BNF is ambiguous:


expr ::= num

| expr expr

To make it unambiguous, I want the to be

10/10/2005

Left associative:
expr ::= num | expr num
Right Associative:
expr ::= num | num expr

P. Van Roy, CIESC tutorials

81

Ambiguity resolution
for binary operators (3)

(B) Precedence Rules


Given two different binary operators op1 and op2
a1 op1 a2 op2 a3

If a1 op1 a2 op2 a3 is interpreted as (a1 op1 a2) op2 a3,


then op1 has a higher precedence than op2.

Ifa1 op a2 op a3 is interpreted as a1 op1 (a2 op2 a3),


then op2 has a higher precedence than op1.

10/10/2005

P. Van Roy, CIESC tutorials

82

Ambiguity resolution
for binary operators (4)

Example: This BNF is ambiguous:


<expr> ::= <num> | <expr> + <expr> | <expr> * <expr>

1+2*3
<expr
>
<expr
>
<num
>
1

<expr
>

<expr
>
<expr <num
>
>
<num
3
>
2

<expr
>

<expr + <expr
>
>
<num <expr
* <expr
>
>
>
<num
<num
1
>
>

Which One?

(1+2)*3
10/10/2005

1+(2*3)
P. Van Roy, CIESC tutorials

83

Ambiguity resolution
for binary operators (5)
Example: This BNF is ambiguous:
<expr> ::= <num> | <expr> + <expr> | <expr> * <expr>
To make it unambiguous, I want
(Case 1) + to be of a higher precedence than *
<expr> ::= <expr2> | <expr2> * <expr>
<expr2>::= <num> | <num> + <expr2>
<expr
2>

1+2*3

<num
>
1

10/10/2005

(1+2)*3

P. Van Roy, CIESC tutorials

<expr
>

<expr
>
<expr <expr
2>
2>
<num <num
>
>
2

3
84

Ambiguity resolution
for binary operators (6)
Example: This BNF is ambiguous:
<expr> ::= <num> | <expr> + <expr> | <expr> * <expr>
To make it unambiguous, I want
(Case 2) * to be of a higher precedence than +
<expr> ::= <expr2> | <expr2> + <expr>
<expr2>::= <num> | <num> * <expr2>

1+2*3

<expr
2>
<num
>
1

1+(2*3)
10/10/2005

P. Van Roy, CIESC tutorials

<expr
>

<expr
>
<expr
2>

<num
>

<expr
2>
<num
>
3
85

Ambiguity of operators

For binary operators, we have to specify


the associativity of the operators, and
The precedence of the operators
Alternatively, rewrite the grammar rules to get rid
of ambiguity

10/10/2005

P. Van Roy, CIESC tutorials

86

Ambiguity of operators

Version #1 of BNF:
<E> ::= <E> + <E> |
<E> - <E> | <E> * <E> | <E> /<E>|
<num> | <var> | (<E>)
Is the grammar ambiguous? Yes
Version #2 of BNF:
<E> ::= <E> + <T> | <E> - <T> | <T>
<T> ::= <T> * <F> | <T> / <F> | <F>
<F> ::= <num> | <var> | (<E>)
10/10/2005

P. Van Roy, CIESC tutorials

87

Ambiguity (Dangling-Else Ambiguity)

Ambiguity in general

Ambiguous grammar is NOT restricted to just binary operation:


Example:
<S>

::= if <E> then <S>


|
if <E> then <S> else <S>

String:
if <E1> then if <E2> then <S1> else <S2>
Parse Tree???

<S>

<S>

if <E1> then<S>

if <E1>then <S> else <S2>

if <E2> then<S1> else <S2>

10/10/2005

P. Van Roy, CIESC tutorials

if <E2> then <S1>

88

Context-sensitive grammars

For practical languages context-free grammar is


not enough

A condition on context is sometimes added

10/10/2005

for example: identifier must be declared before use

P. Van Roy, CIESC tutorials

89

Context-free and
context-sensitive grammars

Easy to read and


understand
Defines superset of
language

Context-free grammar
(e.g. with EBNF)

Expresses restrictions
imposed by language
Renders grammar rules
context sensitive

Set of extra conditions

10/10/2005

P. Van Roy, CIESC tutorials

90

Lesson 3:
Introduction to
Language Semantics

10/10/2005

P. Van Roy, CIESC tutorials

91

Language semantics

Defines what a program does when executed


Goals

simple
allow programmer to reason about program
(correctness, execution time, and memory use)

How to achieve for a practical language used


to build complex systems (millions lines of
code)?
The kernel language approach

10/10/2005

P. Van Roy, CIESC tutorials

92

Kerne language approach (1)

Define simple language (kernel language)


Define its computation model

how language constructs (statements) manipulate


(create and transform) data structures

Define mapping scheme (translation) of full


programming language into kernel language
Two kinds of translations

10/10/2005

linguistic abstractions
syntactic sugar
P. Van Roy, CIESC tutorials

93

Kernel language approach (2)


Provides useful abstractions
for programmer
Can be extended with linguistic
abstractions

fun {Sqr X} X*X end


B = {Sqr {Sqr A}}

practical language
translation

kernel language
Easy to understand and reason
with
Has a precise (formal) semantics
10/10/2005

P. Van Roy, CIESC tutorials

proc {Sqr X Y}
{ * X X Y}
end
local T in
{Sqr A T}
{Sqr T B}
end
94

Linguistic abstractions syntactic


sugar (1)

Linguistic abstractions provide higher level concepts

programmer uses to model and reason about programs


(systems)
examples: functions (fun), iterations (for), classes and objects
(class)

Functions (calls) are translated to procedures (calls)


Translation answers questions about functions, for example,
what does this expression do: {F1 {F2 X} {F3 X}}

10/10/2005

P. Van Roy, CIESC tutorials

95

Linguistic abstractions syntactic


sugar (2)

Linguistic abstractions:
provide higher level concepts
Syntactic sugar:
short cuts and conveniences to
improve readability

if N==1 then [1]


else
local L in

end
end

if N==1 then [1]


else L in

end

10/10/2005

P. Van Roy, CIESC tutorials

96

Approaches to semantics
Programming Language
Operational model

Kernel Language
Aid programmer
in reasoning and
understanding

Formal calculus

Abstract machine

Aid theoretician in mathematical


Aid implementor
study of programming: -calculus, Efficient execution on
predicate calculus, -calculus
a real machine

Our goal!
10/10/2005

P. Van Roy, CIESC tutorials

97

Sequential declarative
computation model (first model)

Single assignment store

Kernel language syntax


Environment

declarative (dataflow) variables and values (together called entities)


values and their types

maps textual variable names (variable identifiers) into entities in the store

Execution of kernel language statements

10/10/2005

execution stack of statements (defines control)


store
transforms store by sequence of steps

P. Van Roy, CIESC tutorials

98

Lexical scoping (1)

Lexical scoping tells us for each identifier occurrence, exactly


which declaration the occurrence corresponds to
Let us first define free and bound identifier occurrences
An identifier occurrence is bound with respect to a statement
s if it is in the scope of a declaration inside s
A variable identifier is declared either by a local statement,
as a parameter of a procedure, or implicitly declared by a
case statement
An identifier occurrence is free otherwise
In a running program every identifier is bound (i.e., declared)

10/10/2005

P. Van Roy, CIESC tutorials

99

Lexical scoping (2)

proc {P X}
local Y in Y = 1 {Browse Y} end
X=Y
end
Free Occurrences

10/10/2005

Bound Occurrences

P. Van Roy, CIESC tutorials

100

Lexical scoping (3)

local Arg1 Arg2 in


Arg1 = 111*111
Arg2 = 999*999
Res = Arg1*Arg2
end
Free Occurrence

Bound Occurrences: Arg1 and Arg2 in the


body of the local statement

This is not a runnable program!


10/10/2005

P. Van Roy, CIESC tutorials

101

Lexical scoping (4)

local Res in
local Arg1 Arg2 in
Arg1 = 111*111
Arg2 = 999*999
Res = Arg1*Arg2
end
{Browse Res}
end
This is a runnable program (there are no free identifier occurrences) !

10/10/2005

P. Van Roy, CIESC tutorials

102

Lexical scoping (5)


local P Q in
proc {P} {Q} end
proc {Q} {Browse hello} end
local Q in
proc {Q} {Browse hi} end
{P}
end
end

10/10/2005

P. Van Roy, CIESC tutorials

103

Procedure abstraction

Any statement can be abstracted to a procedure by selecting


some of the free variable identifier occurrences and enclosing
the statement into a procedure with the identifiers as
paramenters
if X >= Y then Z = X else Z = Y end
Abstracting over all variables
proc {Max X Y Z}
if X >= Y then Z = X else Z = Y end
end
Abstracting over just X and Z
proc {LowerBound X Z}
if X >= Y then Z = X else Z = Y end
end

10/10/2005

P. Van Roy, CIESC tutorials

104

Procedure values (1)

What do procedure values look like in memory (in the store)?


Constructing a procedure value in the store is not simple
because a procedure may have external references

local P Q in
P = proc {$} {Q} end
Q = proc {$} {Browse hello} end
local Q in
Q = proc {$} {Browse hi} end
{P}
end
end
10/10/2005

P. Van Roy, CIESC tutorials

105

Procedure values (2)


P

x1

( , )

proc {$} {Q} end

Q x2

local P Q in
P = proc {$} {Q
Q} end
Q = proc {$} {Browse hello} end
x2 ( , )
local Q in
Q = proc {$} {Browse hi} end
{P}
end
proc {$} {Browse hello} end
end

10/10/2005

P. Van Roy, CIESC tutorials

Browse x0

106

Our roadmap to semantics

Single assignment store


Kernel language syntax
Values and types
Environments
Statements and statement stack
Execution steps

10/10/2005

P. Van Roy, CIESC tutorials

107

Lesson 4:
Declarative
Programming

10/10/2005

P. Van Roy, CIESC tutorials

108

Declarative operations (1)

An operation is declarative if whenever it is called with the


same arguments, it returns the same results independent of
any other computation state
A declarative operation is:

Independent (depends only on its arguments, nothing else)


Stateless (no internal state is remembered between calls)
Deterministic (call with same operations always give same
results)

Declarative operations can be composed together to yield


other declarative components

10/10/2005

All basic operations of the declarative model are declarative and


combining them always gives declarative components

P. Van Roy, CIESC tutorials

109

Declarative operations (2)


Arguments

Declarative
operation

Results

rest of computation
10/10/2005

P. Van Roy, CIESC tutorials

110

Why declarative components (1)

There are two reasons why they are important:


(Programming in the large) A declarative component can be written,
tested, and proved correct independent of other components and of
its own past history.

The complexity (reasoning complexity) of a program composed of


declarative components is the sum of the complexity of the components
In general the reasoning complexity of programs that are composed of
nondeclarative components explodes because of the intimate
interaction between components

(Programming in the small) Programs written in the declarative


model are much easier to reason about than programs written in
more expressive models (e.g., an object-oriented model).

10/10/2005

Simple algebraic and logical reasoning techniques can be used


P. Van Roy, CIESC tutorials

111

Why declarative components (2)

Since declarative components are Given


mathematical functions, algebraic
f (a) = a 2
reasoning is possible i.e.
We can replace f (a ) in any other
substituting equals for equals
equation
The declarative model of chapter 4
2
4
b
=
7
f
(
a
)
becomes
b
=
a
guarantees that all programs
written are declarative
Declarative components can be
written in models that allow stateful
data types, but there is no
guarantee

10/10/2005

P. Van Roy, CIESC tutorials

112

Classification of
declarative programming
Descriptive
Declarative
programming

Observational

Functional
programming

Programmable
Definitional

Declarative
model

The word declarative means many things to


many people. Lets try to eliminate the
confusion.
The basic intuition is to program by defining
the what without explaining the how
10/10/2005

P. Van Roy, CIESC tutorials

Deterministic
logic programming

Nondeterministic
logic programming

113

Descriptive language
s ::=
|
|
|
|

skip
x = y
x = record
s1 s2
local x in s1 end

empty statement
variable-variable binding
variable-value binding
sequential composition
declaration

Other descriptive languages include HTML and XML

10/10/2005

P. Van Roy, CIESC tutorials

114

Descriptive language
<person id = 530101-xxx>
<name> Seif </name>
<age> 48 </age>
</person>

Other descriptive languages include HTML and XML

10/10/2005

P. Van Roy, CIESC tutorials

115

Kernel language syntax


The following defines the syntax of a statement, s denotes a statement
s ::=
|
|
|
|
|
|
|

skip
empty statement
x = y
variable-variable binding
x = v
variable-value binding
s1 s2
sequential composition
local x in s1 end
declaration
if x then s1 else s2 end
conditional
{ x y1 yn }
procedural application
case x of pattern then s1 else s2 end
pattern matching

v ::= ...
pattern
10/10/2005

value expression
::= ...
P. Van Roy, CIESC tutorials

116

Value expressions
v ::= procedure | record | number
procedure ::= proc {$ y1 yn} s end
record, pattern ::= literal
|
literal (feature1 : x1 featuren : xn)
literal ::= atom | bool
feature ::= int | atom | bool
bool

::= true | false

number
10/10/2005

::= int | float


P. Van Roy, CIESC tutorials

117

Why the kernel language is


declarative

All basic operations are declarative


Given that the components (substatements) are
declarative, we can see that

sequential composition
local statement
procedure definition
procedure call
if statement
try statement

are all declarative


10/10/2005

P. Van Roy, CIESC tutorials

118

Programming with lists

Defining types
Simple list functions

Nth, Member, Append, Reverse, Length

Mergesort

10/10/2005

P. Van Roy, CIESC tutorials

119

User defined data types

A list is defined as a special subset of the record datatype


A list Xs is either

Other subsets of the record datatype are also useful, for


example one may define a binary tree (btree) to be:

X|Xr where Xr is a list, or


nil

node(key:K value:V left:LT right:RT) where LT and BT are binary


trees, or
leaf

This begs for a notation to concisely define subtypes of


records

10/10/2005

P. Van Roy, CIESC tutorials

120

Defining types
list ::= value | list [] nil

defines a list type where the elements can be of any type


list T ::= T | list [] nil

defines a type function that given the type of the parameter T


returns a type, e.g. list int
btree T ::= node(key: literal value:T left: btree T right: btree T)
[] leaf(key: literal value:T)

Procedure types are denoted by proc{T1 Tn}

Function types are denoted by fun{T1 Tn}:T and is equivalent


to proc{T1 Tn T}

Examples: fun{list list }: list

10/10/2005

P. Van Roy, CIESC tutorials

121

Lists

General lists have the following definition


list T ::= T | list [] nil

The most useful elementary procedures on lists


can be found in the Base module List of the Mozart
system
Induction method on lists, assume we want to
prove a property P(Xs) for all lists Xs

1.
2.

10/10/2005

The Base: prove P(Xs) for Xs equals to nil, [X], and [X Y]


The Induction step: Assume P(Xs) hold, and prove
P(X|Xs) for arbitrary X of type T
P. Van Roy, CIESC tutorials

122

Constructive method for


programs on lists

General lists have the following definition


list T ::= T | list T [] nil

The task is to write a program {Task Xs1 Xsn}


Select one or more of the arguments Xsi
Construct the task for Xsi equals to nil, [X], and [X
Y]
The recursive step: assume {Task Xsi } is
constructed, and design the program for {Task
X|Xsi } for arbitrary X of type T

1.
2.

3.

10/10/2005

P. Van Roy, CIESC tutorials

123

Simple functions on lists

1.
2.
3.
4.
5.

Some of these functions exist in the library module List:


{Nth Xs N}, returns the Nth element of Xs
{Append Xs Ys}, returns a list which is the
concatenation of Xs followed by Ys
{Reverse Xs} returns the elements of Xs in a reverse
order, e.g. {Reverse [1 2 3]} is [3 2 1]
Sorting lists, MergeSort
Generic operations of lists, e.g. performing an operation
on all the elements of a list, filtering a list with respect to
a predicate P

10/10/2005

P. Van Roy, CIESC tutorials

124

The Nth function


Define a function that gets the Nth element of a list
Nth is of type fun{$ list T int}:T ,
Reasoning: select N, two cases N=1, and N>1:
N=1:
{Nth Xs 1} Xs.1
N>1: assume we have the solution for {Nth Xr N-1} for a
smaller list Xr, then {Nth X|Xr N} {Nth Xr N-1}
fun {Nth Xs N}
X|Xr = Xs in
if N==1 then X
elseif N>1 then {Nth Xr N-1}
end
end

10/10/2005

P. Van Roy, CIESC tutorials

125

The Nth function


fun {Nth Xs N}
X|Xr = Xs in
if N==1 then X
elseif N>1 then {Nth Xr N-1}
end
end

10/10/2005

fun {Nth Xs N}
if N==1 then Xs.1
elseif N>1 then {Nth Xs.2 N-1}
end
end

P. Van Roy, CIESC tutorials

126

The Nth function


Define a function that gets the Nth element of a list
Nth is of type fun{$ list T int}:T ,
fun {Nth Xs N}
if N==1 then Xs.1
elseif N>1 then {Nth Xs.2 N-1}
end
end
There are two situations where the program fails:

N > length of Xs, (we get a situation where Xs is nil) or


N is not positive, (we get a missing else condition)

Getting the nth element takes time proportional to n

10/10/2005

P. Van Roy, CIESC tutorials

127

The Member function


Member is of type fun{$ value list value}:bool ,
fun {Member E Xs}
case Xs
of nil then false
[] X|Xr then
if X==E then true else {Member E Xr} end
end
end
X==E orelse {Member E Xr} is equivalent to
if X==E then true else {Member E Xr} end
In the worst case, the whole list Xs is traversed, i.e., worst
case behavior is the length of Xs, and on average half of the
list
10/10/2005
P. Van Roy, CIESC tutorials
128

The Append function


fun {Append Xs Ys}
case Xs
of nil then Ys
[] X|Xr then X|{Append Xr Ys}
end
end
The inductive reasoning is on the first argument Xs
Appending Xs and Ys is proportional to the length of the first list
declare Xs0 = [1 2] Ys = [a b] Zs0 = {Append Xs0 Ys}
Observe that Xs0, Ys0 and Zs0 exist after Append
A new copy of Xs0, call it Xs0, is constructed with an unbound
variable attached to the end: 1|2|X, thereafter X is bound to Ys

10/10/2005

P. Van Roy, CIESC tutorials

129

The Append function


proc {Append Xs Ys Zs}
case Xs
of nil then Zs = Ys
[] X|Xr then Zr in
Zs = X|Zr
{Append Xr Ys Zr}
end
end
declare Xs0 = [1 2] Ys = [a b] Zs0 = {Append Xs0 Ys}
Observe that Xs0, Ys and Zs0 exist after Append
A new copy of Xs0, call it Xs0, is constructed with an unbound
variable attached to the end: 1|2|X, thereafter X is bound to Ys
10/10/2005

P. Van Roy, CIESC tutorials

130

Append execution (overview)


Stack: [{Append 1|2|nil [a b] zs0}] Store: {zs0, ...}
Stack: [ {Append 2|nil [a b] zs1} ] Store: {zs0 = 1|zs1, zs1, ... }
Stack: [ {Append nil [a b] zs2} ] Store: {zs0 = 1|zs1, zs1=2|zs2, zs2, ...}
Stack: [ zs2 = [a b] ]
Store: {zs0 = 1|zs1, zs1=2|zs2, zs2, ...}
Stack: [ ]
Store: {zs0 = 1|zs1, zs1=2|zs2, zs2= a|b|nil, ...}

10/10/2005

P. Van Roy, CIESC tutorials

131

Reverse
fun {Reverse Xs}
case Xs
of nil then nil
[] X|Xr then {Append {Reverse Xr} [X]}
end
end

Xs0 = 1 | [2 3 4]

reverse of Xs1 [4 3 2]

Xs1
append [4 3 2] and [1]
10/10/2005

P. Van Roy, CIESC tutorials

132

Length
fun {Length Xs}
case Xs
of nil then 0
[] X|Xr then 1+{Length Xr}
end
end
Inductive reasoning on Xs
10/10/2005

P. Van Roy, CIESC tutorials

133

Merging two sorted lists


Merging two sorted lists
{Merge [3 5 10] [2 5 6]} [2 3 5 5 6 10]
fun{Merge list T list T }: list T , where T is either int,
float, or atom
fun {Merge Xs Ys}
case Xs # Ys
of nil # Ys then Ys
[] Xs # nil then Xs
[] (X|Xr) # (Y|Yr) then
if X =< Y then X|{Merge Xr Ys}
else Y|{Merge Xs Yr} end
end
end
10/10/2005
P. Van Roy, CIESC tutorials

134

Sorting with Mergesort

1.
2.
3.

{MergeSort list T }: list T ; T is either int, float,


atom
MergeSort uses a divide-and-conquer strategy
Split the list into two smaller lists of roughly equal
size
Use MergeSort (recursively) to sort the two smaller
lists
Merge the two sorted lists to get the final result

10/10/2005

P. Van Roy, CIESC tutorials

135

Sorting with Mergesort


L11
L1

split

merge

L12
L

S1

S12

split

merge

L21
L2

split

P. Van Roy, CIESC tutorials

S21
merge

L22
10/10/2005

S11

S2

S22
136

Sorting with Mergesort

1.
2.
3.

{MergeSort list T }: list T ; T is either int, float, atom


MergeSort uses a divide-and-conquer strategy
Split the list into two smaller lists of roughly equal size
Use MergeSort (recursively) to sort the two smaller lists
Merge the two sorted lists to get the final result

fun {MergeSort Xs}


case Xs
of nil then nil
[] [X] then Xs
else Ys Zs in
{Split Xs Ys Zs}
{Merge {MergeSort Ys} {MergeSort Zs}}
end
end
10/10/2005

P. Van Roy, CIESC tutorials

137

Split
proc {Split Xs Ys Zs}
case Xs
of nil then Ys = nil Zs = nil
[] [X] then Ys = Xs Zs = nil
[] X1|X2|Xr then Yr Zr in
Ys = X1|Yr
Zs = X2|Zr
{Split Xr Yr Zr}
end
end
10/10/2005

P. Van Roy, CIESC tutorials

138

Lesson 5:
Stateful Programming

10/10/2005

P. Van Roy, CIESC tutorials

139

Lesson 5

Programming with state (cells)


We extend the declarative kernel language
with one additional concept, namely a
mutable container (cell)
As we will see, the main advantage of state is
modularity

10/10/2005

P. Van Roy, CIESC tutorials

140

Explicit state (1)


The box O
An Interface that hides
the state

State as a group
of memory cells
Group of functions and
procedures that operate
on the state
10/10/2005

The box O can remember


information between
independent invocations,
it has a memory
The basic elements of
explicit state
Index datatypes
Basic techniques and
ideas of using state in
program design

P. Van Roy, CIESC tutorials

141

Explicit state (2)


The box O
An Interface that hides
the state

State as a group
of memory cells
Group of functions and
procedures that operate
on the state
10/10/2005

What is the difference


between implicit state
and explicit state
What is the difference
between state in general
and encapsulate state
Component based
programming and objectoriented programming
Abstract data types using
encapsulated state

P. Van Roy, CIESC tutorials

142

What is state?

State is a sequence of
values in time that
contains the
intermediate results of a
desired computation
Declarative programs
can also have state
according to this
definition
Consider the following
program

10/10/2005

fun {Sum Xs A}
case Xs
of X|Xr then {Sum Xr A+X}
[] nil then A
end
end
{Show {Sum [1 2 3 4] 0}}

P. Van Roy, CIESC tutorials

143

What is implicit state?


The two arguments Xs and
A
represent an implicit state
Xs
A
[1 2 3 4]
0
[2 3 4]
1
[3 4]
3
[4]
6
nil
10
10/10/2005

fun {Sum Xs A}
case Xs
of X|Xr then {Sum Xr A+X}
[] nil then A
end
end
{Show {Sum [1 2 3 4] 0}}

P. Van Roy, CIESC tutorials

144

What is explicit state:


Example?
An unbound
variable
A cell C is created
with initial value 5
X is bound to C

X
C

5
C

The cell C, which X is


bound to, is assigned
the value 6

10/10/2005

P. Van Roy, CIESC tutorials

145

What is explicit state:


Example?
An unbound
variable
A cell C is created
with initialvalue 5
X is bound to C

X
C

5
C

The cell C, which X is


bound to, is assigned
the value 6

10/10/2005

P. Van Roy, CIESC tutorials

The cell is a value


container with a unique
identity
X is really bound to
the identity of the cell
When the cell is
assigned, X does not
change

146

What is explicit state?

X = {NewCell I}

Example: X = {NewCell 0}
X:=J

Creates a cell with initial value I


Binds X to the identity of the cell

Assumes X is bound to a cell C (otherwise exception)


Changes the content of C to become J

Y = @X

10/10/2005

Assumes X is bound to a cell C (otherwise exception)


Binds Y to the value contained in C
P. Van Roy, CIESC tutorials

147

Examples (1)

X = {NewCell 0}

X:=5

Y=X

Y:=10

10/10/2005

@X == 10 % returns true
X == Y % returns true

10

P. Van Roy, CIESC tutorials

148

Examples (2)

X = {NewCell 10}
Y = {NewCell 10}

X == Y % returns false
Because X and Y refer to
different cells, with different
identities

10/10/2005

10

10

@X == @Y
returns true
P. Van Roy, CIESC tutorials

149

Examples (3)

X = {NewCell 0}

X:=5

Y=X

Y:=10

X == 10
returns true

10/10/2005

Y
X

10

Y
P. Van Roy, CIESC tutorials

150

The model extended with cells


Semantic stack
(Thread 1)

10/10/2005

.....

Semantic stack
(Thread n)

w = f(x)
z = person(a:y)
y = 1
u = 2
x

1: w
2: x
....
....

single assignment
store

mutable store

P. Van Roy, CIESC tutorials

151

The stateful model


s ::= skip
| s1 s2
| ...
| thread s1 end
| {NewCell x c}
| {Exchange c x y}

empty statement
statement sequence
thread creation
cell creation
cell exchange

Exchange: bind x to the old content of c and set the


content of the cell c to y
10/10/2005

P. Van Roy, CIESC tutorials

152

The stateful model


| {NewCell x c}
| {Exchange c x y}

cell creation
cell exchange

Exchange: bind x to the old content of c and set the


content of the cell c to y

proc {Assign C X} {Exchange C _ X} end


fun {Access C} X in {Exchange C X X} X end
{Assign C X} can be written C:=X
X={Access C} can be written X=@C
10/10/2005

P. Van Roy, CIESC tutorials

153

Do we need explicit state?

Up to now the computation model we


introduced in the previous lectures did not
have any notion of explicit state
An important question is:
Do we need explicit state?
There are a number of reasons for
introducing state. Let us present some of
them important today.

10/10/2005

P. Van Roy, CIESC tutorials

154

Programs that change


their behavior over time

Declarative program: all information is in the arguments

Program

Stateful program: new information can be put inside a


running program
Program

10/10/2005

P. Van Roy, CIESC tutorials

155

Modular programs

A system (program) is modular if changes (updates)


to the program are confined to the components
where the functionality is changed
Here is an example where introduction of explicit
state in a well confined way leads to program
modularity compared to programs that are written
using only the declarative model (where every
component is a function)

10/10/2005

P. Van Roy, CIESC tutorials

156

Modularity of explicit state (1)

Assume we have
three persons, P, U1,
and U2
P is a programmer
who developed a
component M that
provides two functions
F and G
U1 and U2 are
system builders that
use the component M

10/10/2005

fun {MF}
fun {F ...}
Definition of F
end
fun {G ...}
Definition of G
end
in export(f:F g:G)
end
M = {MF}

P. Van Roy, CIESC tutorials

157

Modularity of explicit state (2)

Assume we have
three persons, P, U1,
and U2
P is a programmer
who developed a
component M that
provides two functions
F and G
U1 and U2 are
system builders that
use the component M

10/10/2005

functor MF
export f:F g:G
define
fun {F ...}
Definition of F
end
fun {G ...}
Definition of G
end
end

P. Van Roy, CIESC tutorials

158

Modularity of explicit state (3)

User U2 has a demanding


application
He wants to extend the
module M to enable him to
monitor how many times
the function F is invoked in
his application
He goes to P, and asks him
to do so without changing
the interface to M

10/10/2005

fun {M}
fun {F ...}
Definition of F
end
fun {G ...}
Definition of G
end
in export(f:F g:G)
end

P. Van Roy, CIESC tutorials

159

Modularity of explicit state (4)

This cannot be done in the declarative model


because F cannot remember its previous
invocations
The only way is to change the interface to F by
adding two extra arguments FIn and FOut:
fun {F ... +FIn ?FOut} FOut = FIn+1 ... end
The rest of the program always remembers the
previous number of invocations (FIn), and FOut
returns the new number of invocations
But this changes the interface!

10/10/2005

P. Van Roy, CIESC tutorials

160

Modularity of explicit state (5)

A cell is created when


MF is called
Due to lexical scoping
the cell is only visible to
the created version of F
and Count
The M.f did not change
New function M.c is
available
X is hidden: only
visible inside M
(encapsulated state)

10/10/2005

fun {MF}
X = {NewCell 0}
fun {F ...}
X := @X+1
Definition of F
end
fun {G ...} Definition of G end
fun {Count} @ X end
in export(f:F g:G c:Count)
end
M = {MF}

P. Van Roy, CIESC tutorials

161

Relationship between the declarative


model and the stateful model

Declarative programming guarantees by


construction that each procedure computes a
function
This means each component (and
subcomponent) is a function
It is possible to use encapsulated state (cells) so
that a component is declarative from outside,
and stateful from the inside
Considered as a black-box the program
procedure is still a function

10/10/2005

P. Van Roy, CIESC tutorials

162

Programs with accumulators (1)


local
fun {Sum1 Xs A}
case Xs
of X|Xr then {Sum1 Xr A+X}
[] nil then A
end
end
in
fun {Sum Xs}
{Sum1 Xs 0}
end
end

10/10/2005

P. Van Roy, CIESC tutorials

163

Programs with accumulators (2)


local
fun {Sum Xs}
fun {Sum1 Xs A}
fun {Sum1 Xs}
case Xs
case Xs
of X|Xr then {Sum1 Xr A+X}
of X|Xr then
[] nil then A
end
A:=X+@A
end
{Sum1 Xr}
in
[] nil then @A
fun {Sum Xs}
end
{Sum1 Xs 0}
end
end
end
A = {NewCell 0}

in {Sum1 Xs} end


10/10/2005

P. Van Roy, CIESC tutorials

164

Programs with accumulators (3)


local
fun {Sum Xs}
fun {Sum1 Xs A}
A = {NewCell 0}
case Xs
of X|Xr then {Sum1 Xr A+X} in
{ForAll Xs
[] nil then A
end
proc {$ X}
end
A:=X+@A
in
end}
fun {Sum Xs}
@A
{Sum1 Xs 0}
end
end
end

10/10/2005

P. Van Roy, CIESC tutorials

165

Programs with accumulators (4)


local
fun {Sum1 Xs A}
case Xs
of X|Xr then {Sum1 Xr A+X}
[] nil then A
end
end
in
fun {Sum Xs}
{Sum1 Xs 0}
end
end

10/10/2005

fun {Sum Xs}


A = {NewCell 0}
in
for X in Xs do
A:=X+@A
end
@A
end
The state is encapsulated
inside each procedure
invocation

P. Van Roy, CIESC tutorials

166

Lesson 6:
Language Semantics and
the Abstract Machine

10/10/2005

P. Van Roy, CIESC tutorials

167

Lesson 6: semantics with an


abstract machine

This lesson and the next shows how we teach


semantics
We define rigorously an abstract machine and show
how to use it for real programs
The lectures on semantics are considered by
students to be among the most difficult part of the
course

10/10/2005

The abstract machine is a mathematical formalism unlike


what the students have seen before
I teach semantics in the second-year course, together with
practical exercises
P. Van Roy, CIESC tutorials

168

Semantic concepts

Single-assignment store
Environment
Semantic statement
Execution state
Computation

10/10/2005

P. Van Roy, CIESC tutorials

169

Abstract machine

Performs a computation
A computation is a sequence of execution states
Execution state

Semantic statement

stack of semantic statements


single assignment store
statement
environment

Environment maps variable identifiers to store


entities

10/10/2005

P. Van Roy, CIESC tutorials

170

Single-assignment store

Single assignment store

set of store variables


partitioned into

sets of variables that are equal but unbound


variables bound to value

Example store

10/10/2005

{x1, x2=x3, x4=a|x2}

x1
unbound
x2, x3 equal and unbound
x4
bound to partial value a|x2
P. Van Roy, CIESC tutorials

171

Environment

Environment

maps variable identifiers to entities in store


written as set of pairs
Xx

variable identifier
store variable

X
x

Example environment

10/10/2005

{ X x, Y y }

maps identifier X to store variable x


maps identifier Y to store variable y

P. Van Roy, CIESC tutorials

172

Environment and store

Given: environment E, store

Looking up value for variable identifier X:

find store variable in environment E(X)


take value from for E(X)

Example:
={x1, x2=x3, x4=a|x2}
E = { X x1, Y x4 }
E(X) = x1
and no information in on x1
E(Y) = x4
and binds x4 to a|x2

10/10/2005

P. Van Roy, CIESC tutorials

173

Calculating with environments

Program execution looks up values

assume store
given variable identifier x
E(x) is value in store

Program execution modifies environments

10/10/2005

for example: declaration


adding new mappings from identifiers
overwrite existing mappings
restricting mappings to sets of variables

P. Van Roy, CIESC tutorials

174

Environment adjunction

Given: Environment E
E + {x1x1, , xnxn}
is new environment E with mappings added:

10/10/2005

always take store entity from new mappings


might overwrite old mappings

P. Van Roy, CIESC tutorials

175

Environment restriction

Given: Environment E
E | {x1, , xn}
is new environment E where only mappings
for {x1, , xn} are retained from E

10/10/2005

P. Van Roy, CIESC tutorials

176

Adjunction example

E0 = { Y 1 }

E1 = E0 + { X 2 }

corresponds to { X 2, Y 1 }
E1(X) = 2

E2 = E1 + { X 3 }

10/10/2005

corresponds to { X 3, Y 1 }
E2(X) = 3
P. Van Roy, CIESC tutorials

177

Why adjunction?
E0
local X in
X=2
local X in
X=3
{ Y}
end

end

E2

E1

E0
10/10/2005

P. Van Roy, CIESC tutorials

178

Semantic statements

To actually execute a statement, we need:

an environment to map identifiers

a store to find values

modified with execution of each statement


each statement has its own environment
all statements modify same store
single store

Semantic statement

10/10/2005

( s, E )

pair of (statement, environment)


P. Van Roy, CIESC tutorials

179

Stacks of statements

Execution maintains a stack of semantic


statements
ST
[(s1, E1), , (sn, En)]

always topmost statement (s1, E1) executes first

rest of stack: what needs to be done

Also called: semantic stack

10/10/2005

P. Van Roy, CIESC tutorials

180

Execution state

Execution state

( ST, )

pair of ( stack of semantic statements, store )

Computation
(ST1, 1) (ST2, 2) (ST3, 3)

10/10/2005

sequence of execution states

P. Van Roy, CIESC tutorials

181

Program execution

Initial execution state


( [(s,)] , )

empty store
stack with semantic statement

single statement s, empty environment

At each execution step

[(s,)]

pop topmost element of semantic stack


execute according to statement

If semantic stack empty, execution stops

10/10/2005

P. Van Roy, CIESC tutorials

182

Semantic stack states

Semantic stack can be in run-time states

terminated
runnable
suspended

stack is empty
can do execution step
stack not empty, no execution
step possible

Statements

10/10/2005

non-suspending
suspending

can always execute


need values from store
dataflow behavior
P. Van Roy, CIESC tutorials

183

Summary of lesson 6

Single assignment store


Environments

Semantic statements
Semantic stacks
Execution state
Program execution

adjunction, restriction

E
E + {} E | {}

(s, E)
[(s, E) ]
(ST, )

runnable, terminated, suspended

Statements

10/10/2005

suspending, non-suspending
P. Van Roy, CIESC tutorials

184

Lesson 7:
Executing the
Abstract Machine

10/10/2005

P. Van Roy, CIESC tutorials

185

Lesson 7: executing the


abstract machine

Simple statements

skip and sequential composition


variable declaration
store manipulation
conditional

Computing with procedures (next lecture)

10/10/2005

lexical scoping
closures
procedures as values
procedure call
P. Van Roy, CIESC tutorials

186

Simple statements
s denotes a statement
s ::=
|
|
|
|
|

skip
x = y
x = v
s1 s2
local x in s1 end
if x then s1 else s2 end

v ::= ...

10/10/2005

empty statement
variable-variable binding
variable-value binding
sequential composition
declaration
conditional
value expression

P. Van Roy, CIESC tutorials

187

Executing skip

Execution of semantic statement


(skip, E)
Do nothing

10/10/2005

means: continue with next statement


non-suspending statement

P. Van Roy, CIESC tutorials

188

skip
(skip, E)
ST

ST

No effect on store

Non-suspending statement

10/10/2005

P. Van Roy, CIESC tutorials

189

skip
(skip, E)
ST

ST

Remember: topmost statement is always


popped!

10/10/2005

P. Van Roy, CIESC tutorials

190

Executing sequential
composition

Semantic statement is
(s1 s2, E)
Push in following order

s2
s1

executes after
executes next

Statement is non-suspending

10/10/2005

P. Van Roy, CIESC tutorials

191

Sequential composition
(s1, E)
(s1 s2, E)
ST

(s2, E)

ST

Decompose statement sequences

10/10/2005

environment is given to both statements


P. Van Roy, CIESC tutorials

192

Executing local

Semantic statement is
(local x in s end, E)
Execute as follows

create new variable y in store


create new environment E = E + {x y}
push (s, E)

Statement is non-suspending

10/10/2005

P. Van Roy, CIESC tutorials

193

local
local x in
s
end

ST

(s, E)

ST

With E = E + {x y}

10/10/2005

P. Van Roy, CIESC tutorials

194

Variable-variable equality

Semantic statement is
(x = y, E)
Execute as follows

bind E(x) and E(y) in store

Statement is non-suspending

10/10/2005

P. Van Roy, CIESC tutorials

195

Variable-value equality

Semantic statement is
(x = v, E)
with v number or record
Execute as follows

create value v in store

use variables as defined by E

bind E(x) and v in store

Statement is non-suspending

10/10/2005

P. Van Roy, CIESC tutorials

196

Variable-value equality

Semantic statement is
(x = v, E)
with v number or record
Execute as follows

create value v in store

use variables as defined by E

bind E(x) and v in store

What about
procedures?

Statement is non-suspending

10/10/2005

P. Van Roy, CIESC tutorials

197

Suspending statements

All statements so far can always execute

Conditional?

non-suspending (or immediate)

requires condition x to be bound variable


activation condition: x is bound (determined)

Foundation of dataflow execution

10/10/2005

P. Van Roy, CIESC tutorials

198

Executing if

Semantic statement is
(if x then s1 else s2 end, E)
If activation condition x bound true

if E(x) bound to true


if E(x) bound to false
otherwise, raise error

push s1
push s2

Otherwise, suspend

10/10/2005

P. Van Roy, CIESC tutorials

199

Example
local X in
local B in
B=true
if B then X=1 else skip end
end
end

10/10/2005

P. Van Roy, CIESC tutorials

200

Example: initial state


([(local X in
local B in
B=true
if B then X=1 else skip end
end
end, )],
)

Start with empty store and empty


environment

10/10/2005

P. Van Roy, CIESC tutorials

201

Example: local
([(local B in
B=true
if B then X=1 else skip end
end,
{X x})],
{x})

Create new store variable x


Continue with new environment

10/10/2005

P. Van Roy, CIESC tutorials

202

Example: local
([(B=true
if B then X=1 else skip end
,
{B b, X x})],
{b,x})

Create new store variable b


Continue with new environment

10/10/2005

P. Van Roy, CIESC tutorials

203

Example:
sequential composition
([(B=true, {B b, X x}),
(if B then X=1
else skip end, {B b, X x})],
{b,x})

Decompose to two statements


Stack has now two semantic statements

10/10/2005

P. Van Roy, CIESC tutorials

204

Example:
variable-value assignment
([(if B then X=1
else skip end, {B b, X x})],
{b=true, x})

Environment maps B to b
Bind b to true

10/10/2005

P. Van Roy, CIESC tutorials

205

Example: if
([(X=1, {B b, X x})],
{b=true, x})

Environment maps B to b
Store binds b to true, continue with then

10/10/2005

P. Van Roy, CIESC tutorials

206

Example:
variable-value assignment
([],
{b=true, x=1})

Environment maps X to x
Binds x to 1
Computation terminates as stack is empty

10/10/2005

P. Van Roy, CIESC tutorials

207

Summary

Semantic statement execute by

popping itself
creating environment
manipulating store
pushing new statements

always
local
local, =
local, if
sequential composition

Semantic statement can suspend

10/10/2005

activation condition
read store
P. Van Roy, CIESC tutorials

208

Lesson 8:
Declarative Concurrency

10/10/2005

P. Van Roy, CIESC tutorials

209

Declarative concurrency

Declarative concurrency is the simplest form


of concurrency

There are no race conditions, i.e., no observable


nondeterminism
That is why we see this form of concurrency first

We add one concept to the declarative kernel


language, namely the thread
We see the other forms of concurrency,
message-passing and shared-state
concurrency, later

10/10/2005

P. Van Roy, CIESC tutorials

210

Concurrency in general

Some programs are best written as a set of activities that run


independently (concurrent programs)
Concurrency is essential for interaction with the external
environment
Examples includes GUI (Graphical User Interface), operating
systems, etc.
Also programs that are written independently but interact only
when needed (client-server applications)
This lecture is about declarative concurrency: programs with
no observable nondeterminism, the result is a function
Independent procedures that execute on their pace and may
communicate through shared dataflow variables

10/10/2005

P. Van Roy, CIESC tutorials

211

Overview

Programming with threads

Lazy execution

The model is augmented with just one concept, namely threads


This introduces many new programming techniques: stream
communication, order-determining concurrency, coroutines,
concurrent composition
Lazy execution introduces a second concept, namely by-need
synchronization (waiting until a variable is needed)
This introduces another set of new techniques: demand-driven
computations, lazy streams, and list comprehensions
In this tutorial we will not see more about lazy execution; see the
textbook!

Soft real-time programming

10/10/2005

P. Van Roy, CIESC tutorials

212

The sequential model


Statements are
Semantic
executed sequentially Stack
from a single semantic
stack

Single-assignment
store

10/10/2005

w=a
z = person(age: y)
x
y = 42
u

P. Van Roy, CIESC tutorials

213

The concurrent model


Multiple semantic
stacks (threads)

Single-assignment
store

10/10/2005

Semantic
Stack 1

Semantic
Stack N

w=a
z = person(age: y)
x
y = 42
u

P. Van Roy, CIESC tutorials

214

Concurrent declarative model


The following defines the syntax of a statement, s denotes a statement
s ::=
|
|
|
|
|
|
|
|
|

10/10/2005

skip
empty statement
x = y
variable-variable binding
x = v
variable-value binding
s1 s2
sequential composition
local x in s1 end
declaration
proc {x y1 yn } s1 end
procedure introduction
if x then s1 else s2 end
conditional
{ x y1 yn }
procedure application
case x of pat then s1 else s2 end
pattern matching
thread s1 end
thread creation

P. Van Roy, CIESC tutorials

215

The concurrent model


Top of Stack, Thread i

ST
thread s1 end,E

Single-assignment
store

10/10/2005

P. Van Roy, CIESC tutorials

216

The concurrent model


Top of Stack, Thread i

ST

s1, E

Single-assignment
store

10/10/2005

P. Van Roy, CIESC tutorials

217

Basic concepts

The model allows multiple statements to execute at the same


time ?
Imagine that these threads really execute in parallel, each has
its own processor, but share the same memory
Reading and writing different variables can be done
simultaneously by different threads, as well as reading the
same variable
Writing the same variable is done sequentially
The above view is in fact equivalent to an interleaving
execution: a totally ordered sequence of computation steps,
where threads take turn doing one or more steps in sequence

10/10/2005

P. Van Roy, CIESC tutorials

218

Causal order

In a sequential program all execution states


are totally ordered
In a concurrent program all execution states
of a given thread are totally ordered
The execution state of the concurrent
program as a whole is partially ordered

10/10/2005

P. Van Roy, CIESC tutorials

219

Total order

In a sequential program all execution states


are totally ordered

sequential
execution
computation step

10/10/2005

P. Van Roy, CIESC tutorials

220

Causal order in the declarative


model

In a concurrent program all execution states of a given thread


are totally ordered
The execution state of the concurrent program is partially
ordered

thread T3
thread T2

fork a thread

thread T1
computation step
10/10/2005

P. Van Roy, CIESC tutorials

221

Causal order in the declarative


model
synchronize on a dataflow variable

bind a dataflow variable


thread T3
x
fork a thread

thread T2
thread T1

computation step
10/10/2005

P. Van Roy, CIESC tutorials

222

Nondeterminism

An execution is nondeterministic if there is a


computation step in which there is a choice what to
do next
Nondeterminism appears naturally when there are
multiple concurrent states

10/10/2005

P. Van Roy, CIESC tutorials

223

Example of nondeterminism
store

Thread 1

Thread 2

x
y=5

x=1

x=3

time
time
The thread that binds x first will continue,
the other thread will raise an exception
10/10/2005

P. Van Roy, CIESC tutorials

224

Nondeterminism

An execution is nondeterministic if there is a


computation step in which there is a choice what to
do next
Nondeterminism appears naturally when there are
multiple concurrent states
In the concurrent declarative model when there is
only one binder for each dataflow variable, the
nondeterminism is not observable on the store (i.e.
the store develops to the same final results)
This means for correctness we can ignore the
concurrency!

10/10/2005

P. Van Roy, CIESC tutorials

225

Scheduling

The choice of which thread to execute next and for how long
is done by a part of the system called the scheduler
A thread is runnable if its next statement to execute is not
blocked on a dataflow variable, otherwise the thread is
suspended
A scheduler is fair if it does not starve a runnable thread
I.e. all runnable thread execute eventually
Fair scheduling make it easy to reason about programs
Otherwise some prefectly runnable program will never get its
share

10/10/2005

P. Van Roy, CIESC tutorials

226

The semantics

In the sequential model we had:


(ST , )

ST is a stack of semantic statements


is the single assignment store
In the concurrent model we have:
(MST , )
MST is a (multi)set of stacks of semantic statements
is the single assignment store

10/10/2005

P. Van Roy, CIESC tutorials

227

The initial execution state


statement

({ [ (s,) ] }, )
stack
store
multiset

10/10/2005

P. Van Roy, CIESC tutorials

228

Execution (the scheduler)

At each step, one runnable semantic stack is selected from


MST (the multiset of stacks), call it ST, i.e., MST = ST MST
Assume the current store is , one computation step is done
that transforms ST to ST and to
The total computation state is transformed from (MST, ) to
(ST MST, )
Which stack is selected, and how many step are tasken is the
task of the scheduler, a good scheduler should be fair, i.e.
each runnable thread will eventually be selected
The computation stops when there is no runnable stack

10/10/2005

P. Van Roy, CIESC tutorials

229

Example of runnable thread


proc {Loop P N}
if N > 0 then
{P} {Loop P N-1}
else skip end
end
thread {Loop
proc {$} {Show 1}
end 1000}
end
thread {Loop
proc {$} {Show 2}
end 1000}
end
10/10/2005

This program will


interleave the execution
of two threads, one
printing 1, and the other
printing 2
We assume a fair
scheduler

P. Van Roy, CIESC tutorials

230

Dataflow computation

Threads suspend of data availability in


dataflow variables
The {Delay X} primitive makes the thread
suspends for X milliseconds, after that the
thread is runnable

declare X
{Browse X}
local Y in
thread {Delay 1000} Y = 10*10 end
X = Y + 100*100
end
10/10/2005

P. Van Roy, CIESC tutorials

231

Illustrating dataflow computation


declare X0 X1 X2 X3
{Browse [X0 X1 X2 X3]}
thread
Y0 Y1 Y2 Y3
in
{Browse [Y0 Y1 Y2 Y3]}
Y0 = X0 + 1
Y1 = X1 + Y0
Y2 = X2 + Y1
Y3 = X3 + Y2
{Browse completed}
end
10/10/2005

P. Van Roy, CIESC tutorials

Enter incrementally
the values of X0 to X3
When X0 is bound the
thread will compute
Y0=X0+1, and will
suspend again until
X1 is bound

232

Concurrent map function (1)


fun {CMap Xs F}
This will fork a thread
case Xs
for each individual
of nil then nil
element in the input list
[] X|Xr then
Each thread will run
thread {F X} end|{CMap Xr F}
only in both the
end
element X and the
end
procedure F is known

10/10/2005

P. Van Roy, CIESC tutorials

233

Concurrent map function (2)


fun {CMap Xs F}
case Xs
of nil then nil
[] X|Xr then thread {F X} end |{CMap Xr F}
end
end

How this really looks like in the kernel language:

proc {CMap Xs F Rs}


case Xs
of nil then Rs = nil
[] X|Xr then R Rr in
Rs = R|Rr
thread R = {F X} end
Rr = {CMap Xr F}
end
end
10/10/2005

P. Van Roy, CIESC tutorials

234

How does it work? (1)

If we enter the following statements:


declare F X Y Z
{Browse thread {CMap X F} end}

A thread executing CMap is created.

It will suspend immediately in the case-statement because X


is unbound.

If we thereafter enter the following statements:


X = 1|2|Y
fun {F X} X*X end

The main thread will traverse the list creating two threads for
the first two arguments of the list

10/10/2005

P. Van Roy, CIESC tutorials

235

How does it work? (2)

The main thread will traverse the list creating two


threads for the first two arguments of the list, namely

thread {F 1} end and thread {F 2} end,


Y = 3|Z
Z = nil

and adding Y=3|nil will complete the computation of


the main thread and the newly created thread
thread {F 3} end, resulting in the final list [1 4 9].

10/10/2005

P. Van Roy, CIESC tutorials

236

Cheap concurrency and


dataflow

Declarative programs
can be easily made
concurrent
Just use the thread
statement where
concurrent is needed

10/10/2005

fun {Fib X}
if X=<2 then 1
else
thread {Fib X-1} end
+ {Fib X-2}
end
end

P. Van Roy, CIESC tutorials

237

Understanding why
fun {Fib X}
if X=<2 then 1
else F1 F2 in
F1 = thread {Fib X-1} end
F2 = {Fib X-2}
Dataflow dependency

F1 + F2
end
end
10/10/2005

P. Van Roy, CIESC tutorials

238

Execution of {Fib 6}
F2
F3
F4

Fork a thread

F1

F2

Synchronize on
result

F2
F5

F3

F1
F2

F3
F6

F4

10/10/2005

Running thread

F1

F2
P. Van Roy, CIESC tutorials

239

Fib run-time statistics

10/10/2005

P. Van Roy, CIESC tutorials

240

Streams

A stream is a sequence of messages

A stream is a list with an unbound tail!

A stream is First-In First-Out channel


The producer augments the stream with new messages,
and the consumer reads the messages, one by one.

producer

10/10/2005

x5 x4 x3 x2 x1

P. Van Roy, CIESC tutorials

consumer

241

Stream communication (1)

The dataflow property of Oz easily enables


writing threads that communicate through
streams in a producer-consumer pattern

A stream is a list that is created incrementally by


one thread (the producer) and subsequently
consumed by one or more threads (the
consumers).

The consumers consume the same elements of


the stream.

10/10/2005

P. Van Roy, CIESC tutorials

242

Stream communication (2)

Producer, that incrementally produces the elements of a


stream
Transducer(s), that transforms the elements of the stream,
giving a new stream
Consumer, that accumulates the results of a stream
thread 1

thread 2

producer

transducer

10/10/2005

thread 3
transducer

P. Van Roy, CIESC tutorials

thread N
consumer

243

Program patterns

The producer, transducers, and the


consumer can, in general, be described by
certain program patterns
We show some of these patterns

10/10/2005

P. Van Roy, CIESC tutorials

244

Producer pattern
fun {Producer State}
if {More State} then
X = {Produce State} in
X | {Producer {Transform State}}
else nil end
end
The definitions of More, Produce, and Transform are
problem-dependent
The State could be multiple arguments
The above definition is not a complete program!
10/10/2005

P. Van Roy, CIESC tutorials

245

Example producer
fun {Generate N Limit}
if N=<Limit then
N | {Generate N+1 Limit}
else nil end
end

fun {Producer State}


if {More State} then
X = {Produce State} in
X | {Producer {Transform State}}
else nil end
end

The State is the two arguments N and Limit


The predicate More is the condition N=<Limit
The Transform function (N,Limit) (N+1,Limit)

10/10/2005

P. Van Roy, CIESC tutorials

246

Consumer pattern
fun {Consumer State InStream}
The consumer suspends until
case InStream
InStream is either a cons or a nil
of nil then {Final State}
[] X | RestInStream then
NextState = {Consume X State} in
{Consumer NextState RestInStream}
end
end
Final and Consume are problem-dependent
10/10/2005

P. Van Roy, CIESC tutorials

247

Example consumer
fun {Sum A Xs}
case Xs
of X|Xr then {Sum A+X Xr}
[] nil then A
end
end

fun {Consumer State InStream}


case InStream
of nil then {Final State}
[] X | RestInStream then
NextState = {Consume X State} in
{Consumer NextState RestInStream}
end
end

The State is A
Final is just the identity function on State
Consume takes X and State X + State

10/10/2005

P. Van Roy, CIESC tutorials

248

Transducer pattern (1)


fun {Transducer State Instream}
case InStream
of nil then nil
[] X | RestInStream then
NextState#TX = {Transform X State}
TX | {Consumer NextState RestInStream}
end
end
A transducer keeps its state in State, receives
messages on InStream and sends messages on
OutStream
10/10/2005

P. Van Roy, CIESC tutorials

249

Transducer pattern (2)


fun {Transducer State Instream}
case InStream
of nil then nil
[] X | RestInStream then
if {Test X#State} then
NextState#TX = {Transform X State}
TX | {Consumer NextState RestInStream}
else {Consumer NextState RestInStream} end
end
end
A transducer keeps its state in State, receives messages on
InStream and sends messages on OutStream
10/10/2005

P. Van Roy, CIESC tutorials

250

Example transducer
IsOdd
6 5 4 3 2 1
Generate

fun {Filter Xs F}
case Xs
of nil then nil
[] X|Xr then
if {F X} then X|{Filter Xr
F}
else {Filter Xr F} end
end
end
10/10/2005

5 3

Filter

Filter is a transducer that


takes an Instream and incremently
produces an Outstream that satisfies
the predicate FF
local Xs Ys in
thread Xs = {Generate 1 100} end
thread Ys = {Filter Xs IsOdd} end
thread {Browse Ys} end
end
P. Van Roy, CIESC tutorials

251

Larger example:
The sieve of Eratosthenes

Produces prime numbers


It takes a stream 2...N, peels off 2 from the rest of the stream
Delivers the rest to the next sieve

Sieve
Xs

Xr

10/10/2005

X|Zs

Filter

Ys

Sieve

P. Van Roy, CIESC tutorials

Zs

252

Sieve
fun {Sieve Xs}
case Xs
of nil then nil
[] X|Xr then Ys in
thread
Ys = {Filter Xr fun {$ Y} Y mod X \= 0 end}
end
X | {Sieve Ys}
end
end
The program forks a filter thread on each sieve call

10/10/2005

P. Van Roy, CIESC tutorials

253

Example call
local Xs Ys in
thread Xs = {Generate 2 100000} end
thread Ys = {Sieve Xs} end
thread for Y in Ys do {Show Y} end end
end

10/10/2005

P. Van Roy, CIESC tutorials

254

Larger example:
The sieve of Eratosthenes

Produces prime numbers


It takes a stream 2...N, peels off 2 from the rest of the stream
Delivers the rest to the next sieve

7 | 11 |...

Filter 2

10/10/2005

Filter 3

Filter 5

P. Van Roy, CIESC tutorials

Sieve

255

Limitation of eager stream


processing

The producer might be much faster than the


consumer
This will produce a large intermediate stream
that requires potentially unbounded memory
storage
producer

10/10/2005

x5 x4 x3 x2 x1

P. Van Roy, CIESC tutorials

consumer

256

Solutions

1.

2.

3.

10/10/2005

There are three alternatives:


Play with the speed of the different threads, i.e. play with
the scheduler to make the producer slower (not a
recommended solution)
Create a bounded buffer, say of size N, so that the
producer waits automatically when the buffer is full
Use demand-driven approach, where the consumer
activates the producer when it need a new element
(lazy evaluation)
The last two approaches introduce the notion of flowcontrol between concurrent activities (very common)

P. Van Roy, CIESC tutorials

257

Lesson 9:
Object-Oriented
Programming

10/10/2005

P. Van Roy, CIESC tutorials

258

Object-oriented programming

We have gotten so far and we have said almost nothing about


object-oriented programming!
There is much, much more to programming than just objectoriented programming

I will not say much on OOP in this tutorial

We have to resist the pressure by part of industry to reduce


programming to object-oriented programming in Java
The textbook and the slides on the books Web site say a lot; I
suggest you go take a look

Trends show that both concurrent programming and


component-based programming will become much more
important in the future, and that OOP will become a simple
part of these two paradigms

10/10/2005

P. Van Roy, CIESC tutorials

259

Conclusions

10/10/2005

P. Van Roy, CIESC tutorials

260

Conclusions

We have gone through a lot of material in these two


two-hour tutorials

The two main lessons of these tutorials

Probably too much to digest in one sitting


Programming can be taught both broadly (many paradigms)
and deeply (with semantics) to second-year students
Programming can be taught as a unified discipline, in which
each paradigm has its part, not as a set of disjoint
paradigms

Good luck with your programming courses!

10/10/2005

P. Van Roy, CIESC tutorials

261

Anda mungkin juga menyukai