0% found this document useful (0 votes)
0 views

comp3610_slides pld

The document outlines the course COMP3610/6361 on Principles of Programming Languages, taught by A/Prof. Peter Höfner and includes details about the course structure, assessment criteria, and topics covered. It emphasizes the importance of programming languages in software engineering, including syntax, semantics, and pragmatics. The course aims to provide foundational knowledge in programming language theory and design, with a focus on formal semantics and reasoning about programs.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
0 views

comp3610_slides pld

The document outlines the course COMP3610/6361 on Principles of Programming Languages, taught by A/Prof. Peter Höfner and includes details about the course structure, assessment criteria, and topics covered. It emphasizes the importance of programming languages in software engineering, including syntax, semantics, and pragmatics. The course aims to provide foundational knowledge in programming language theory and design, with a focus on formal semantics and reasoning about programs.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 524

COMP3610/6361

Principles of Programming Languages

Peter Höfner

Oct 25, 2023

1
Section 0

Admin

2
Lecturer

• A/Prof. Peter Höfner


CSIT, Room N234 (Building 108)
[email protected]
+61 2 6125 0159

Consultation
Thursday 12pm – 1pm, or by appointment

3
CoLecturer and Tutors

• Dr Fabian Muelboeck
[email protected]

• Abhaas Goyal
[email protected]

• Weiyou Wang
[email protected]

4
Lectures

• Wednesday, 3 pm – 5 pm
Thursday, 11 am – 12 pm
• Rm 5.02 Marie Reay, Bldg 155
• Q/A session in Week 12

• Etiquette
▶ engage
▶ feel free to ask questions
▶ we reject behaviour that strays into harassment,
no matter how mild

5
Tutorials

• join one of the 2 tutorials


• Thursday, 3pm – 5pm (Rm 5.02 Marie Reay)
Friday, 1pm – 2pm (Rm 4.03 Marie Reay)
• from Week 2 onwards

• Summary
▶ your chance to discuss problems
▶ discuss home work
▶ discuss additional exercises

6
Plan/Schedule I

Resources
web: https://cs.anu.edu.au/courses/comp3610/
wattle: https://wattlecourses.anu.edu.au/course/view.php?id=41142
edstem: https://edstem.org/
(you will be registered at the end of the week)

Workload
The average student workload is 130 hours for a six unit course.
That is roughly 11 hours/week.
https://policies.anu.edu.au/ppl/document/ANUP_000691

7
Plan/Schedule II
Assessment criteria
• Quizz: 0% (for feedback only)
• Assignments: 35%, 4 assignments (35marks)
• Oral exam: 65% (65 marks) [hurdle]
• hurdle: minimum of 40% in the final exam
Assessments (tentative)
No Hand Out Hand In Marks
0 31/07 03/08 0
1 02/08 10/08 5
2 16/08 31/08 10
3 20/09 12/10 10
4 18/10 02/11 10

8
About the Course I

This course is an introduction to


the theory and design of programming languages.

9
About the Course II
Topics (tentative)
The following schedule is tentative and likely to change.
Topic
0 Admin
1 introduction
2 IMP and its Operational Semantics
3 Types
4 Derivation and Proofs
5 Functions, Call-by-Value, Call-by-Name
6 Typing for Call-By-Value
7 Data Types and Subtyping
8 Denotational Semantics
9 Axiomatic Semantics
10 Concurrency
11 Formal Verification

10
About the Course IV

Disclaimer
This is has been redesigned fairly recently.
The material in these notes has been drawn from several different
sources, including the books and similar courses at some other
universities. Any errors are of course all the author’s own work.
As it is a newly designed course, changes in timetabling are quite likely.
Feedback (oral, email, survey, . . . ) is highly appreciated.

11
Academic Integrity

• never misrepresent the work of others as your own


• if you take ideas from elsewhere
you must say so with utmost clarity

12
Reading Material

• Glynn Winskel. The Formal Semantics of Programming Languages


– An Introduction. MIT Press, 1993. ISBN 978-0-262-73103-4
• Robert Harper. Practical Foundations for Programming Languages.
Cambridge University Press, 2016. ISBN 978-1-107-15030-0
• Shriram Krishnamurthi. Programming Languages: Application and
Interpretation (2nd edition) Open Textbook Library, 2017
• additional reading material can be found online

13
Section 1

Introduction

14
Foundational Knowledge of Disciplines
Mechanical Engineering
Students learn about torque
d(r × ω) dω dr
=r× + ×ω
dt dt dt

Figure: Sydney Harbour Bridge under construction [NMA]

15
Foundational Knowledge of Disciplines
Electrical Engineering / Astro Physics
Students learn about complex impedance
ejωt = cos(ωt) + j sin(ωt)

Figure: Geomagnetic Storm alters Earth’s Magnetic field [Wikipedia]

16
Foundational Knowledge of Disciplines
Civil Engineering / Surveying
Students learn about trigonometry
sin(θ + ϕ) = sin θ cos ϕ + cos θ sin ϕ

Figure: Surveying Swan River, WA [Wikipedia]

17
Foundational Knowledge of Disciplines
Software Engineering / Computer Science
Students learn about ???

Figure: First Ariane 5 Flight, 1996 [ESA] Figure: Heartbleed, 2014 [Wikipedia]

18
Programming Languages

Programming Languages: basic tools of computing


• what are programming languages?
• do they provide basic laws of software engineering?
• do they allow formal reasoning in the sense of above laws?

19
Constituents

• the syntax of programs:


the alphabet of symbols and a description of the well-formed
expressions, phrases, programs, etc.
• the semantics:
the meaning of programs, or how they behave
• often also the pragmatics:
description and examples of how the various features of the
language are intended to be used

20
Use of Semantics

• understand a particular language


what you can depend on as a programmer;
what you must provide as a compiler writer
• as a tool for language design:
▶ clear language design
▶ express design choices, understand language features and interaction
▶ for proving properties of a language, eg type safety, decidability of type
inference.
• prove properties of particular programs

21
Style of Description (Syntax and Semantics)

• natural language
• definition ‘by’ compiler behaviour
• mathematically

22
Introductory Examples: C

In C, if initially x has value 3, what is the value of the following?


x++ + x++ + x++ + x++

Is it different to the following?


x++ + x++ + ++x + ++x

23
Introductory Examples: C♯
In C♯ , what is the output of the following?
delegate i n t IntThunk ( ) ;
class C {
p u b l i c s t a t i c v o i d Main ( ) {
I n t T h u n k [ ] f u n c s = new I n t T h u n k [ 1 1 ] ;
f o r ( i n t i = 0 ; i <= 1 0 ; i ++)
{
funcs [ i ] = delegate ( ) { r e t u r n i ; } ;
}
foreach ( IntThunk f i n funcs )
{
System . Console . W r i t e L i n e ( f ( ) ) ;
}
}
}

24
Introductory Examples: JavaScript

f u n c t i o n bar ( x ) {
return function () {
var x = x ;
return x ;
};
}

v a r f = bar ( 2 0 0 ) ;

f ()

25
About This Course

• background: mathematical description of syntax by means of formal


grammars, e.g. BNF (see COMP1600)
clear, concise and precise
• aim I: mathematical definitions of semantics/behaviour
• aim II: understand principles of program design
(for a toy language)
• aim III: reasoning about programs

26
Use of formal, mathematical semantics

Implementation issues
Machine-independent specification of behaviour. Correctness of program
analyses and optimisations.

Language design
Can bring to light ambiguities and unforeseen subtleties in programming
language constructs. Mathematical tools used for semantics can suggest
useful new programming styles. (E.g. influence of Church’s lambda
calculus (circa 1934) on functional programming).

Verification
Basis of methods for reasoning about program properties and program
specifications.

27
Styles of semantics

Operational
Meanings for program phrases defined in terms of the steps of
computation they can take during program execution.

Denotational
Meanings for program phrases defined abstractly as elements of some
suitable mathematical structure.

Axiomatic
Meanings for program phrases defined indirectly via the axioms and
rules of some logic of program properties.

28
Section 2

IMP
and its Operational Semantics

29
‘Toy’ languages

• real programming languages are large


many features, redundant constructs
• focus on particular aspects and abstract from others (scale up later)
• even small languages can involve delicate design choices.

30
Design choices, from Micro to Macro

• basic values
• evaluation order
• what is guaranteed at compile-time and run-time
• how effects are controlled
• how concurrency is supported
• how information hiding is enforceable
• how large-scale development and re-use are supported
• ...

31
IMP1 – Introductory Example

IMP is an imperative language with store locations, conditionals and


while loop.
For example
l2 := 0 ;
while !l1 ≥ 1 do (
l2 := !l2 + !l1 ;
l1 := !l1 + −1
)
with initial store {l1 7→ 3, l2 7→ 0}.

1 Basically the same as in Winskel 1993 (IMP) and in Hennessy 1990 (WhileL)
32
IMP – Syntax
Booleans b ∈ B = {true, false}
Integers (Values) n ∈ Z = {. . . , −1, 0, 1, . . . }
Locations l ∈ L = {l, l0 , l1 , l2 , . . . }

Operations op ::= + | ≥

Expressions

E ::= n | b | E op E |
l := E | !l |
skip | E ; E |
if E then E else E
while E do E

33
Transition systems

A transition system consists of


• a set Config of configurations (or states), and
• a binary relation −→⊆ Config × Config.
The relation −→ is called the transition or reduction relation:
c −→ c′ reads as ‘state c can make a transition to state c′ ’.
(see DFA/NFA)

34
IMP Semantics (1 of 4) – Configurations

Stores are (finite) partial functions L ⇀ Z.


For example, {l1 7→ 3, l3 7→ 42}

Configurations are pairs ⟨E , s⟩ of an expression E and a store s.


For example, ⟨l := 2 + !l , {l 7→ 3}⟩.

Transitions have the form ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩.


For example, ⟨l := 2 + !l , {l 7→ 3}⟩ −→ ⟨l := 2 + 3 , {l 7→ 3}⟩

35
Transitions – Examples

Transitions are single computation steps.


For example

⟨l := 2 + !l , {l 7→ 3}⟩
−→ ⟨l := 2 + 3 , {l 7→ 3}⟩
−→ ⟨l := 5 , {l 7→ 3}⟩
−→ ⟨skip , {l 7→ 5}⟩
−→
̸

Keep going until reaching a value v, an expression in V = B ∪ Z ∪ {skip}.


A configuration ⟨E , s⟩ is stuck if E is not a value and ⟨E , s⟩ −→.
̸

36
IMP Semantics (2 of 4) – Rules (basic operations)

(op+) ⟨n1 + n2 , s⟩ −→ ⟨n , s⟩ if n = n1 + n2

(op≥) ⟨n1 ≥ n2 , s⟩ −→ ⟨b , s⟩ if b = (n1 ≥ n2 )

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(op1)
⟨E1 op E2 , s⟩ −→ ⟨E1′ op E2 , s′ ⟩

⟨E2 , s⟩ −→ ⟨E2′ , s′ ⟩
(op2)
⟨v op E2 , s⟩ −→ ⟨v op E2′ , s′ ⟩

37
Rules (basic operations) – Examples

Find the possible sequences of transitions for

⟨(2 + 3) + (4 + 5) , ∅⟩

The answer is 14 – but how do we show this formally?

38
IMP Semantics (3 of 4) – Store and Sequencing

(deref) ⟨!l , s⟩ −→ ⟨n , s⟩ if l ∈ dom(s) and s(l) = n

(assign1) ⟨l := n , s⟩ −→ ⟨skip , s + {l 7→ n}⟩ if l ∈ dom(s)

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(assign2)
⟨l := E , s⟩ −→ ⟨l := E ′ , s′ ⟩

(seq1) ⟨skip ; E2 , s⟩ −→ ⟨E2 , s⟩

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(seq2)
⟨E1 ; E2 , s⟩ −→ ⟨E1′ ; E2 , s′ ⟩

39
Store and Sequencing – Examples

⟨l := 3 ; !l , {l 7→ 0}}⟩ −→ ⟨skip ; !l , {l 7→ 3}⟩


−→ ⟨!l , {l 7→ 3}⟩
−→ ⟨3 , {l 7→ 3}⟩

40
Store and Sequencing – Examples

⟨l := 3 ; l := !l , {l 7→ 0}⟩ −→ ?

⟨42 + !l , ∅⟩ −→ ?

41
IMP Semantics (4 of 4) – Conditionals and While

(if1) ⟨if true then E2 else E3 , s⟩ −→ ⟨E2 , s⟩

(if2) ⟨if false then E2 else E3 , s⟩ −→ ⟨E3 , s⟩

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(if3)
⟨if E1 then E2 else E3 , s⟩ −→ ⟨if E1′ then E2 else E3 , s′ ⟩

(while)
⟨while E1 do E2 , s⟩ −→ ⟨if E1 then (E2 ; while E1 do E2 ) else skip , s⟩

42
IMP – Examples

If

E = l2 := 0 ; while !l1 ≥ 1 do (l2 := !l2 + !l1 ; l1 := !l1 + −1)
s = {l1 7→ 3, l2 7→ 0}

then

⟨E , s⟩ −→∗ ?

43
Determinacy

Theorem (Determinacy)
If ⟨E , s⟩ −→ ⟨E1 , s1 ⟩ and ⟨E , s⟩ −→ ⟨E2 , s2 ⟩
then ⟨E1 , s1 ⟩ = ⟨E2 , s2 ⟩.

Proof.
later ⊔

44
Reminder

• basic and simple imperative while-language


• with formal semantics
• given in the format structural operational semantics
A B
• rules usually have the form
C
(special rule is C, which we often write as C)
• derivation tree
( R 4) ( R 5)
B1 B2
( R 3) ( R 2)
A B
( R 1)
C

45
Language design I
Order of Evaluation
IMP uses left-to-right evaluation. For example

⟨(l := 1 ; 0) + (l := 2 ; 0) , {l 7→ 0}⟩ −→5 ⟨0 , {l 7→ 2}⟩

For right-to-left we could use


⟨E2 , s⟩ −→ ⟨E2′ , s′ ⟩
(op1’)
⟨E1 op E2 , s⟩ −→ ⟨E1 op E2′ , s′ ⟩

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(op2’)
⟨E1 op v , s⟩ −→ ⟨E1′ op v , s′ ⟩

In this language

⟨(l := 1 ; 0) + (l := 2 ; 0) , {l 7→ 0}⟩ −→5 ⟨0 , {l 7→ 1}⟩

46
Language design II
Assignment results
Recall
(assign1) ⟨l := n , s⟩ −→ ⟨skip , s + {l 7→ n}⟩ if l ∈ dom(s)

(seq1) ⟨skip ; E2 , s⟩ −→ ⟨E2 , s⟩

We have chosen to map an assignment to skip, and e1 ; e2 to progress


iff e1 = skip.

Instead we could have chosen the following.


(assign1’) ⟨l := n , s⟩ −→ ⟨n , s + {l 7→ n}⟩ if l ∈ dom(s)

(seq1’) ⟨v ; E2 , s⟩ −→ ⟨E2 , s⟩

47
Language design III

Store initialisation
Recall
(deref) ⟨!l , s⟩ −→ ⟨n , s⟩ if l ∈ dom(s) and s(l) = n

Assumes l ∈ dom(s).

Instead we could have


• initialise all locations to 0, or
• allow assignments to an l ̸∈ dom(s).

48
Language design IV

Storable values
• our language only allows integer values (store: L ⇀ Z)
• could we store any value? Could we store locations, or even
programs?
• store is global and cannot create new locations

49
Language design V

Operators and Basic values


• Booleans are different from integers (unlike in C)
• Implementation is (probably) different to semantics
Exercise: fix the semantics to match 32-bit integers

50
Expressiveness

Is our language expressive enough to write ‘interesting’ programs?


• yes: it is Turing-powerful
Exercise: try to encode an arbitrary Turing machine in IMP
• no: no support for standard feature, such as functions, lists, trees,
objects, modules, . . .
Is the language too expressive?
• yes: we would like to exclude programs such as 3 + true
clearly 3 and true are of different type

51
Section 3

Types

52
Type systems

• describe when programs make sense


• prevent certain kinds of errors
• structure programs
• guide language design

Ideally, well-typed programs do not get stuck.

53
Run-time errors
Trapped errors
Cause execution to halt immediately.
Examples: jumping to an illegal address, raising a top-level exception.
Innocuous?

Untrapped errors
May go unnoticed for a while and later cause arbitrary behaviour.
Examples: accessing data past the end of an array, security loopholes in
Java abstract machines.
Insidious!

Given a precise definition of what constitutes an untrapped run-time


error, then a language is safe if all its syntactically legal programs cannot
cause such errors. Usually, safety is desirable. Moreover, we’d like as
few trapped errors as possible.

54
Formal type systems

We define a ternary relation Γ ⊢ E : T


expression E has type T , under assumptions Γ on the types of locations
that may occur in E.

For example (according to the definition coming up):


• {} ⊢ if true then 2 else 3 + 4 : int
• l1 : intref ⊢ if !l1 ≥ 3 then !l1 else 3 : int
• {} ⊬ 3 + true : T for any type T
• {} ⊬ if true then 3 else true : int

55
Types of IMP

Types of expressions

T ::= int | bool | unit


Types of locations

Tloc ::= intref


We write T and Tloc for the sets of all terms of these grammars.
• Γ ranges over TypeEnv, the finite partial function from L ⇀ Z
• notation: write l1 : intref, . . . , lk : intref instead of
{l1 7→ intref, . . . , lk 7→ intref}

56
Type Judgement (1 of 3)

(int) Γ ⊢ n : int if n ∈ Z
(bool) Γ ⊢ b : bool if b ∈ B = {true, false}

Γ ⊢ E1 : int Γ ⊢ E2 : int
(op+)
Γ ⊢ E1 + E2 : int

Γ ⊢ E1 : int Γ ⊢ E2 : int
(op≥)
Γ ⊢ E1 ≥ E2 : bool

Γ ⊢ E1 : bool Γ ⊢ E2 : T Γ ⊢ E3 : T
(if)
Γ ⊢ if E1 then E2 else E3 : T

57
Type Judgement – Example

Prove that {} ⊢ if false then 2 else 3 + 4 : int.

( INT ) ( INT )
{} ⊢ 3 : int {} ⊢ 4 : int
( BOOL ) ( INT ) ( OP+)
{} ⊢ false : bool {} ⊢ 2 : int {} ⊢ 3 + 4 : int
( IF )
{} ⊢ if false then 2 else 3 + 4 : int

58
Type Judgement (2 of 3)

Γ(l) = intref Γ ⊢ E : int


(assign)
Γ ⊢ l := E : unit

Γ(l) = intref
(deref)
Γ ⊢ !l : int

Here, (for the moment) Γ(l) = intref means l ∈ dom(Γ)

59
Type Judgement (3 of 3)

(skip) Γ ⊢ skip : unit

Γ ⊢ E1 : unit Γ ⊢ E2 : T
(seq)
Γ ⊢ E1 ; E2 : T

Γ ⊢ E1 : bool Γ ⊢ E2 : unit
(while)
Γ ⊢ while E1 do E2 : unit

60
Type Judgement – Properties

Theorem (Progress)
If Γ ⊢ E : T and dom(Γ) ⊆ dom(s) then either E is a value or there exist
E ′ and s′ such that ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩.

Theorem (Type Preservation)


If Γ ⊢ E : T , dom(Γ) ⊆ dom(s) and ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ then Γ ⊢ E ′ : T
and dom(Γ) ⊆ dom(s′ ).

61
Type Safety

Main result: Well-typed programs do not get stuck.


Theorem (Type Safety)
If Γ ⊢ E : T , dom(Γ) ⊆ dom(s), and ⟨E , s⟩ −→∗ ⟨E ′ , s′ ⟩ then either E ′ is
a value with Γ ⊢ E ′ : T , or there exist E ′′ , s′′ such that
⟨E ′ , s′ ⟩ −→ ⟨E ′′ , s′′ ⟩, Γ ⊢ E ′′ : T and dom(Γ) ⊆ dom(s′′ ).

Here, −→∗ means arbitrary many steps in the transition system.

62
Type checking, typeability, and type inference

Type checking problem for a type system:


given Γ, E and T , is Γ ⊢ E : T derivable?

Type inference problem:


given Γ and E, find a type T such that Γ ⊢ E : T is derivable, or show
there is none.

Type inference is usually harder than type checking, for a type T needs
to be computed.

For our type system, though, both are easy.

63
Properties

Theorem (Type inference)


Given Γ and E , one can find T such that Γ ⊢ E : T , or show that there is
none.

Theorem (Decidability of type checking)


Given Γ, E and T , one can decide whether Γ ⊢ E : T holds.

Moreover
Theorem (Uniqueness of typing)
If Γ ⊢ E : T and Γ ⊢ E : T ′ then T = T ′ .

64
Section 4

Proofs (Structural Induction)

65
Why Proofs

• how do we know that the stated theorems are actually true?


intuition is often wrong – we need proof
• proofs strengthen intuition about language features
• examines all the various cases
• can guarantee items such as type safety
• most of our definitions are inductive; we use structural induction

66
(Mathematical) Induction

Mathematical induction proves that we can climb as high as we


like on a ladder, by proving that we can climb onto the bottom
rung (the basis) and that from each rung we can climb up to the
next one (the step).

[Concrete Mathematics (1994), R. Graham]

67
Natural Induction I

A proof by (natural) induction consists of two cases.


The base case proves the statement for n = 0 without assuming any
knowledge of other cases.
The induction step proves that if the statement holds for any given case
n = k, then it must also hold for the next case n = k + 1.

68
Natural Induction II

Theorem
∀n ∈ IN .Φ(n).

Proof.
Base case: show Φ(0)
Induction step: ∀k. Φ(k) =⇒ Φ(k + 1)
For that we fix an arbitrary k.
Assume Φ(k) derive Φ(k + 1). ⊔

n·(n+1)
Example: 0 + 1 + 2 + · · · + n = 2 .

69
Natural Induction III

Theorem
∀n ∈ IN .Φ(n).

Proof.
Base case: show Φ(0)
Induction step: ∀i, k.0 ≤ i ≤ k. Φ(i) =⇒ Φ(k + 1)
For that we fix an arbitrary k.
Assume ϕ(i) for all i ≤ k derive ϕ(k + 1). ⊔

φn −ψ n
Example: Fn = φ−ψ , √
1+ 5
with Fn is the n-th Fibonacci number, φ = 2 (the golden ratio) and

ψ = 1−2 5 .

70
Structural Induction I

• generalisation of natural induction


• prove that some proposition Φ(x) holds for all x of some sort of
recursively defined structure
• requires well-founded partial order

Examples: lists, formulas, trees

71
Structural Induction II

Determinacy structural induction for E


Progress rule induction for Γ ⊢ E : T
(induction over the height of derivation tree)
Type Preservation rule induction for ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
Safety mathematical induction on −→n
Uniqueness of typing ...
Decidability of typability exhibiting an algorithm
Decidability of type checking corollary of other results

72
Structural Induction over Expressions

Prove facts about all expressions, e.g. Determinacy?


Theorem (Determinacy)
If ⟨E , s⟩ −→ ⟨E1 , s1 ⟩ and ⟨E , s⟩ −→ ⟨E2 , s2 ⟩
then ⟨E1 , s1 ⟩ = ⟨E2 , s2 ⟩.

Do not forget the elided universal quantifiers.


Theorem (Determinacy)
For all E, s, E1 , s1 , E2 and s2 ,
if ⟨E , s⟩ −→ ⟨E1 , s1 ⟩ and ⟨E , s⟩ −→ ⟨E2 , s2 ⟩
then ⟨E1 , s1 ⟩ = ⟨E2 , s2 ⟩.

73
Abstract Syntax

Remember the definition of expressions:

E ::= n | b | E op E |
l := E | !l |
if E then E else E |
skip | E ; E |
while E do E

This defines an (infinite) set of expressions.

74
Abstract Syntax Tree I

Example: if !l ≥ 0 then skip else (skip ; l := 0)

if then else

≥ skip ;

!l 0 skip l :=

75
Abstract Syntax Tree II

• equivalent expressions are not the same, e.g., 2 + 2 ̸= 4


+

2 2 4
• ambiguity, e.g., (1 + 2) + 3 ̸= 1 + (2 + 3)
+ +
+ 3 1 +

1 2 2 3
Parentheses are only used for disambiguation – they are not part of
the grammar

76
Structural Induction (for abstract syntax)

Theorem
∀E ∈ IMP. Φ(E)

Proof.
Base case(s): show Φ(E) for each unary tree constructor (leaf)
Induction step(s): show it for the remaining constructors

∀c. ∀E1 , . . . Ek . (Φ(E1 ) ∧ · · · ∧ Φ(Ek )) =⇒ Φ(c(E1 , . . . , Ek ))


77
Structural Induction (syntax IMP)

To show ∀E ∈ IMP. Φ(E).


base cases
nullary: Φ(skip)
∀b ∈ B. Φ(b)
∀n ∈ Z. Φ(n)
∀l ∈ L. Φ(!l)
steps
unary: ∀l ∈ L. ∀E. Φ(E) =⇒ Φ(l := E)
binary: ∀op. ∀E1 , E2 . (Φ(E1 ) ∧ Φ(E2 )) =⇒ Φ(E1 op E2 )
∀E1 , E2 . (Φ(E1 ) ∧ Φ(E2 )) =⇒ Φ(E1 ; E2 )
∀E1 , E2 . (Φ(E1 ) ∧ Φ(E2 )) =⇒ Φ(while E1 do E2 )
ternary: ∀E1 , E2 , E3 . (Φ(E1 ) ∧ Φ(E2 ) ∧ Φ(E3 ))
=⇒ Φ(if E1 then E2 else E3 )

78
Proving Determinacy – Outline

Theorem (Determinacy)
For all E, s, E1 , s1 , E2 and s2 ,
if ⟨E , s⟩ −→ ⟨E1 , s1 ⟩ and ⟨E , s⟩ −→ ⟨E2 , s2 ⟩
then ⟨E1 , s1 ⟩ = ⟨E2 , s2 ⟩.

Proof.
Choose
def
Φ(E) = ∀s, E ′ , s′ , E ′′ , s′′ .
(⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ ∧ ⟨E , s⟩ −→ ⟨E ′′ , s′′ ⟩)
=⇒ ⟨E ′ , s′ ⟩ = ⟨E ′′ , s′′ ⟩

and show Φ(E) by structural induction over E. ⊔


79
Proving Determinacy – Sketch

Some cases on whiteboard

80
Proving Determinacy – auxiliary lemma

Values do not reduce.


Lemma
For all E ∈ IMP, if E is a value then
∀s. ¬(∃E ′ , s′ . ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩).

Proof.
• E is a value iff it is of the form n, b, skip
• By examination of the rules . . .
there is no rule with conclusion of the form ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ for E
a value

81
Inversion I
In proofs involving inductive definitions. one often needs an inversion
property.
Given a tuple in one inductively defined relation, gives you a case
analysis of the possible “last rule” used.
Lemma (Inversion for −→)
If ⟨E , s⟩ −→ ⟨Ê , ŝ⟩ then either
1. (op+): there exists n1 , n2 and n such that E = n1 op n2 , Ê = n,
ŝ = s and n = n1 + n2 ,
(Note: +s have different meanings in this statements), or
2. (op1): there exists E1 , E2 , op and E1′ such that E = E1 op E2 ,
Ê = E1′ op E2 and ⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩, or
3. . . .

82
Inversion II

Lemma (Inversion for ⊢)


If Γ ⊢ E : T then either
• ...

83
Determinacy – Intuition

The intuition behind structural induction over expressions. Consider


(!l + 2) + 3. How can we see that Φ((!l + 2) + 3) holds?

+ 3

!l 2

84
Rule Induction

How to prove the following theorems?


Theorem (Progress)
If Γ ⊢ E : T and dom(Γ) ⊆ dom(s) then either E is a value or there exist
E ′ and s′ such that ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩.

Theorem (Type Preservation)


If Γ ⊢ E : T , dom(Γ) ⊆ dom(s) and ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ then Γ ⊢ E ′ : T
and dom(Γ) ⊆ dom(s′ ).

85
Inductive Definition of −→

What does ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ actually mean?

We defined the transition relation by providing some rules, such as


(op+) ⟨n1 + n2 , s⟩ −→ ⟨n , s⟩ if n = n1 + n2

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(op1)
⟨E1 op E2 , s⟩ −→ ⟨E1′ op E2 , s′ ⟩

These rules (their concrete instances) inductively/recursively define a set


of derivation trees. The last step in the derivation tree defines a step in
the transition system.
We define the (infinite) set of all finite derivation trees

86
Derivation Tree (Transition Relation) – Example

( OP+)
⟨2 + 2 , {}⟩ −→ ⟨4 , {}⟩
( OP 1)
⟨(2 + 2) + 3 , {}⟩ −→ ⟨4 + 3 , {}⟩
( OP 1)
⟨(2 + 2) + 3 ≥ 5 , {}⟩ −→ ⟨4 + 3 ≥ 5 , {}⟩

87
Derivation Tree (Typing Judgement) – Example

Γ(l) = intref
( DERREF ) ( INT )
Γ ⊢!l : int Γ ⊢ 2 : int
( OP +) ( INT )
Γ ⊢ !l + 2 : int Γ ⊢ 3 : int
( OP +)
Γ ⊢ (!l + 2) + 3 : int

88
Principle of Rule Induction I

For any property Φ(a) of elements a of A, and any set of rules which
define a subset SR of A, to prove

∀a ∈ SR . Φ(a)

it is enough to prove that {a | Φ(a)} is closed under the rules,


i.e., for each
h1 . . . hk
c
if Φ(h1 ) ∧ · · · ∧ Φ(hk ) then Φ(c).

89
Principle of Rule Induction II

For any property Φ(a) of elements a of A, and any set of rules which
define a subset SR of A, to prove

∀a ∈ SR . Φ(a)

it is enough to prove that for each

h1 . . . hk
c

if Φ(h1 ) ∧ · · · ∧ Φ(hk ) then Φ(c).

90
Proving Progress I

Theorem (Progress)
If Γ ⊢ E : T and dom(Γ) ⊆ dom(s) then either E is a value or there exist
E ′ and s′ such that ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩.

Proof.
Choose

Φ(Γ, E, T ) = ∀s. dom(Γ) ⊆ dom(s)


=⇒ value(E) ∨ (∃E ′ , s′ . ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩)

We show that for all Γ, E, T , if Γ ⊢ E : T then Φ(Γ, E, T ), by rule


induction on the definition of ⊢. ⊔

91
Proving Progress II

Rule induction for our typing rules means:

(int) ∀Γ, n. Φ(Γ, n, int)


(deref) ∀Γ, l. Γ(l) = intref =⇒ Φ(Γ, !l, int)

(op+) ∀Γ, E1 , E2 . Φ(Γ, E1 , int) ∧ Φ(Γ, E2 , int) ∧ Γ ⊢ E1 : int ∧ Γ ⊢ E2 : int
=⇒ Φ(Γ, E1 + E2 , int)

(seq) ∀Γ, E1 , E2 . Φ(Γ, E1 , unit) ∧ Φ(Γ, E2 , T ) ∧ Γ ⊢ E1 : unit ∧ Γ ⊢ E2 : T
=⇒ Φ(Γ, E1 ; E2 , int)

. . . [10 rules in total]

92
Proving Progress III

Φ(Γ, E, T ) = ∀s. dom(Γ) ⊆ dom(s)


=⇒ value(E) ∨ (∃E ′ , s′ . ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩)

Case (op+):
Γ ⊢ E1 : int Γ ⊢ E2 : int
(op+)
Γ ⊢ E1 + E2 : int

• assume Φ(Γ, E1 , int), Φ(Γ, E2 , int), Γ ⊢ E1 : int and Γ ⊢ E2 : int


• we have to show Φ(Γ, E1 + E2 , int)
• assume an arbitrary but fixed s, and dom(Γ) ⊆ dom(s)
• E1 + E2 is not a value; hence we have to show
∃E ′ , s′ . ⟨E1 + E2 , s⟩ −→ ⟨E ′ , s′ ⟩

93
Proving Progress IV
Case (op+) (cont’d):
• we have to show

∃E ′ , s′ . ⟨E1 + E2 , s⟩ −→ ⟨E ′ , s′ ⟩

• Using Φ(Γ, E1 , int) and Φ(Γ, E2 , int) we have


case E1 reduces. Then E1 + E2 does, by (op1).
case E1 is a value and E2 reduces. Then E1 + E2 does, by (op2).
case E1 and E2 are values; we want to use

(op+) ⟨n1 + n2 , s⟩ −→ ⟨n , s⟩ if n = n1 + n2

we assumed Γ ⊢ E1 : int and Γ ⊢ E2 : int we need E1 = n1 and


E2 = n2 ; then E1 + E2 reduces, by (op+).

94
Proving Progress V

Lemma
For all Γ, E, T , if Γ ⊢ E : T is a value with T = int
then there exists n ∈ Z with E = n.

95
Derivation Tree (Typing Judgement) – Example

Γ(l) = intref
( DEREF ) ( INT )
Γ ⊢ !l : int Γ ⊢ 2 : int
( OP +) ( INT )
Γ ⊢ !l + 2 : int Γ ⊢ 3 : int
( OP +)
Γ ⊢ (!l + 2) + 3 : int

96
Which Induction Principle to Use?

• matter of convenience (all equivalent)


• use an induction principle that matches the definitions

97
Structural Induction (Repetition)

Determinacy structural induction for E


Progress rule induction for Γ ⊢ E : T
(induction over the height of derivation tree)
Type Preservation rule induction for ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
Safety mathematical induction on −→n
Uniqueness of typing ...
Decidability of typability exhibiting an algorithm
Decidability of type checking corollary of other results

98
Why care about Proofs?

1. sometimes it seems hard or pointless to prove things because they


are ‘obvious’, . . .
(in particular with our language)
2. proofs illustrate (and explain) why ‘things are obvious’
3. sometimes the obvious facts are false . . .
4. sometimes the obvious facts are not obvious at all
(in particular for ‘real’ languages)
5. sometimes a proof contains or suggests an algorithm that you need
(proofs that type inference is decidable (for fancier type systems))
6. force a clean language design

99
Section 5

Functions

100
Functions, Methods, Procedures, . . .

• so far IMP was really minimalistic


• the most important ‘add-on’ are functions
• this requires variables and other concepts

101
Examples
add one : : I n t −> I n t
add one n = n + 1

p u b l i c i n t add one ( i n t x ) {
return ( x +1);
}

< s c r i p t t y p e =” t e x t / v b s c r i p t ”>
f u n c t i o n addone ( x )
addone = x+1
end f u n c t i o n
</ s c r i p t >

102
Introductory Examples: C♯
In C♯ , what is the output of the following?
delegate i n t IntThunk ( ) ;
class C {
p u b l i c s t a t i c v o i d Main ( ) {
I n t T h u n k [ ] f u n c s = new I n t T h u n k [ 1 1 ] ;
f o r ( i n t i = 0 ; i <= 1 0 ; i ++)
{
funcs [ i ] = delegate ( ) { r e t u r n i ; } ;
}
foreach ( IntThunk f i n funcs )
{
System . Console . W r i t e L i n e ( f ( ) ) ;
}
}
}
In my opinion, the design was wrong.

103
Functions – Examples

We want include the following expressions:

(fn x : int ⇒ x + 1)
(fn x : int ⇒ x + 1) 7
(fn y : int ⇒ (fn x : int ⇒ x + y))
(fn y : int ⇒ (fn x : int ⇒ x + y)) 1
(fn x : int → int ⇒ (fn y : int ⇒ x (x y)))
(fn x : int → int ⇒ (fn y : int ⇒ x (x y))) (fn x : int ⇒ x + 1)

(fn x : int → int ⇒ (fn y : int ⇒ x (x y))) (fn z : int ⇒ z + 1) 7

104
Functions – Syntax

We extend our syntax:


Variables x ∈ X for a set X = {x, y, z, . . . } (countable)
Expressions
E ::= . . . | (fn x : T ⇒ E) | E E | x
Types

T ::= int | bool | unit | T → T


Tloc ::= intref

105
Variable Shadowing

(fn x : int ⇒ (fn x : int ⇒ x + 1))

106
Alpha conversion

In expressions (fn x : T ⇒ E), variable x is a binder


• inside E, any x (not being a binder themselves and not inside
another (fn x : T ′ ⇒ . . . )) mean the same
• it is the formal parameter of this function
• outside (fn x : T ⇒ E), it does not matter which variable we use – in
fact, we should not be able to tell
For example, (fn x : int ⇒ x + 2) should be the same as
(fn y : int ⇒ y + 2)

Binders are known from many areas of mathematics/logics.

107
Alpha conversion: free and bound variables

An occurrence x in an expression E is free if it is not inside any


(fn x : T ⇒ . . .).
For example:

17
x+y
(fn x : int ⇒ x + 2)
(fn x : int ⇒ x + z)
if y then 2 + x else ((fn x : int ⇒ x + 2) z)

108
Alpha Conversion – Binding Examples

(fn x : int ⇒ x + 2)

(fn x : int ⇒ x + z)

(fn y : int ⇒ y + z)

(fn z : int ⇒ z + z)

(fn x : int ⇒ (fn x : int ⇒ x + 2))

109
Alpha Conversion – Convention

• we want to allow to replace binder x (and all occurrences of x bound


by that x) by another binder y
• if it does not change the binding graph

For example

(fn x : int ⇒ x + z) = (fn y : int ⇒ y + z) ̸= (fn z : int ⇒ z + z)

• called ‘working up to alpha conversion’


• extend abstract syntax trees by pointers

110
Syntax Trees up to Alpha Conversion

(fn x : int ⇒ x + z) = (fn y : int ⇒ y + z) ̸= (fn z : int ⇒ z + z)

Standard abstract syntax trees

(fn x : int ⇒ ) (fn y : int ⇒ ) (fn z : int ⇒ )

+ + +

x z y z z z

111
Syntax Trees up to Alpha Conversion II

(fn x : int ⇒ x + z) = (fn y : int ⇒ y + z) ̸= (fn z : int ⇒ z + z)

Add pointers

(fn • : int ⇒ ) (fn • : int ⇒ ) (fn • : int ⇒ )

+ + +

• z • z • •

112
Syntax Trees up to Alpha Conversion III

(fn x : int ⇒ (fn x : int ⇒ x + 2))


= (fn y : int ⇒ (fn z : int ⇒ z + 2)) ̸= (fn z : int ⇒ (fn y : int ⇒ z + 2))

(fn • : int ⇒ ) (fn • : int ⇒ )

(fn • : int ⇒ ) (fn • : int ⇒ )

+ +

• z • z

113
Syntax Trees up to Alpha Conversion IV
Application and function type

(fn x : int ⇒ x) 7 (fn z : int → int → int ⇒ (fn y : int ⇒ z y y))

(fn • : int → int → int ⇒ )

(fn • : int ⇒ )

@ @

(fn • : int ⇒ ) 7 @ •

• • •

114
De Bruijn indices
• these pointers are known as De Bruijn indices
• each occurrence of a bound variable is represented by the number
of fn-nodes you have to pass

(fn • : int ⇒ (fn • : int ⇒ v0 + 2)) ̸= (fn • : int ⇒ (fn • : int ⇒ v1 + 2))

(fn • : int ⇒ ) (fn • : int ⇒ )

(fn • : int ⇒ ) (fn • : int ⇒ )

+ +

• 2 • 2

115
Free Variables

• free variables of an expression E are the set of variables for which


there is an occurrence of x free in E

fv(x) = {x}
fv(E1 op E2 ) = fv(E1 ) ∪ fv(E2 )
fv((fn x : T ⇒ E)) = fv(E) − {x}

• an expression E is closed if fv(E) = ∅


S
• For a set E of expressions fv(E) = E∈E fv(E)
• these definitions are alpha-invariant
(all forthcoming definitions should be)

116
Substitution – Examples

• semantics of functions will involve substitution (replacement)


• {E/x} E ′ denotes the expression E ′ where all free occurrences of x
are substituted by E

Examples

{3/x} (x ≥ x) = (3 ≥ 3)

{3/x} ((fn x : int ⇒ x + y) x) = (fn x : int ⇒ x + y) 3

{y + 2/x} (fn y : int ⇒ x + y) = (fn z : int ⇒ (y + 2) + z)

117
Substitution
Definition


def E if x = z
{E/z} x =
x otherwise

def
{E/z} (fn x : T ⇒ E1 ) = (fn x : T ⇒ ({E/z} E1 )) if x ̸= z and x ̸∈ fv(E)(∗ )

def
{E/z} (E1 E2 ) = ({E/z} E1 ) ({E/z} E2 )

...

if (∗ ) is false, apply alpha conversion to generate a variant of (fn x : T ⇒ E1 ) to


make (∗ ) true

118
Substitution – Example

Substitution – Example Again

{y + 2/x} (fn y : int ⇒ x + y)


= {y + 2/x} (fn z : int ⇒ x + z)
= (fn z : int ⇒ {y + 2/x} (x + z))
= (fn z : int ⇒ {y + 2/x} x + {y + 2/x} z)
= (fn z : int ⇒ (y + 2) + z)

119
Simultaneous Substitution

• a substitution σ is a finite partial function from variables to


expressions
• notation: {E1 /x1 , . . . , Ek /xk } instead of {x1 7→ E1 , . . . , xk 7→ Ek }
• the formal definition is straight forward

120
Definition Substitution [for completeness]

Let σ be {E1 /x1 , . . . , Ek /xk }.


Moreover, dom(σ) = {x1 , . . . , xk } and ran(σ) = {E1 , . . . , Ek }.

Ei if x = xi (and xi ∈ dom(σ)
σx =
x otherwise
σ (fn x : T ⇒ E) = (fn x : T ⇒ (σ E)) if x ̸∈ dom(σ) and x ̸∈ fv(ran(σ)) (∗ )
σ (E1 E2 ) = (σ E1 ) (σ E2 )
σ n = n
σ (E1 op E2 ) = (σ E1 ) op (σ E2 )
σ (if E1 then E2 else E3 ) = if (σ E1 ) then (σ E2 ) else (σ E3 )
σ b = b
σ skip = skip
σ (l := E) = l := (σ E)
σ (!l) = !l
σ (E1 ; E2 ) = (σ E1 ) ; (σ E2 )
σ (while E1 do E2 ) = while (σ E1 ) do (σ E2 )

121
Function Behaviour

• we are now ready to define the semantics of functions


• there are some choices to be made
▶ call-by-value
▶ call-by-name
▶ call-by-need

122
Function Behaviour

Consider the expression

E = (fn x : unit ⇒ (l := 1) ; x) (l := 2)

What is the transition relation

⟨E , {l 7→ 0}⟩ −→∗ ⟨skip , {l 7→ ???}⟩

123
Choice 1: Call-by-Value
Idea: reduce left-hand-side of application to an fn-term;
then reduce argument to a value;
then replace all occurrences of the formal parameter in the fn-term by
that value.

E = (fn x : unit ⇒ (l := 1) ; x) (l := 2)

⟨E , {l 7→ 0}⟩
−→ ⟨(fn x : unit ⇒ (l := 1) ; x) skip , {l 7→ 2}⟩
−→ ⟨(l := 1) ; skip , {l 7→ 2}⟩
−→ ⟨skip ; skip , {l 7→ 1}⟩
−→ ⟨skip , {l 7→ 1}⟩

124
Call-by-Value – Semantics
Values
v ::= b | n | skip | (fn x : T ⇒ E)

SOS rules
all sos rules we used so far, plus the following

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(app1)
⟨E1 E2 , s⟩ −→ ⟨E1′ E2 , s′ ⟩

⟨E2 , s⟩ −→ ⟨E2′ , s′ ⟩
(app2)
⟨v E2 , s⟩ −→ ⟨v E2′ , s′ ⟩

(fn) ⟨(fn x : T ⇒ E) v , s⟩ −→ ⟨{v/x} E , s⟩

125
Call-by-Value – Example I

⟨(fn x : int ⇒ (fn y : int ⇒ x + y)) (3 + 4) 5 , s⟩



= ⟨ (fn x : int ⇒ (fn y : int ⇒ x + y)) (3 + 4) 5 , s⟩

−→ ⟨ (fn x : int ⇒ (fn y : int ⇒ x + y)) 7 5 , s⟩

−→ ⟨ {7/x} (fn y : int ⇒ x + y) 5 , s⟩
= ⟨(fn y : int ⇒ 7 + y) 5 , s⟩
−→ ⟨{5/y} 7 + y , s⟩
= ⟨7 + 5 , s⟩
−→ ⟨12 , s⟩

126
Call-by-Value – Example II

(fn f : int → int ⇒ f 3) (fn x : int ⇒ (1 + 2) + x) −→∗ ???

127
Choice 2: Call-by-Name
Idea: reduce left-hand-side of application to an fn-term;
then replace all occurrences of the formal parameter in the fn-term by
that argument.

E = (fn x : unit ⇒ (l := 1) ; x) (l := 2)

⟨E , {l 7→ 0}⟩
−→ ⟨(l := 1) ; (l := 2) , {l 7→ 0}⟩
−→ ⟨skip ; (l := 2) , {l 7→ 1}⟩
−→ ⟨l := 2 , {l 7→ 1}⟩
−→ ⟨skip , {l 7→ 2}⟩

128
Call-by-Name – Semantics
SOS rules

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(CBN-app)
⟨E1 E2 , s⟩ −→ ⟨E1′ E2 , s′ ⟩

(CBN-fn) ⟨(fn x : T ⇒ E1 ) E2 , s⟩ −→ ⟨{E2 /x} E1 , s⟩

No evaluation unless needed

⟨(fn x : unit ⇒ skip) (l := 2) , {l 7→ 0}⟩


−→ ⟨{l := 2/x} skip , {l 7→ 0}⟩
= ⟨skip , {l 7→ 0}⟩

but if it is needed, repeated evaluation possible.

129
Choice 3: Full Beta

Idea: allow reductions on left-hand-side and right-hand-side;


any time if left-hand-side is an fn-term;
replace all occurrences of the formal parameter in the fn-term by that
argument; allow reductions inside functions

⟨(fn x : int ⇒ 2 + 2) , s⟩ −→ ⟨(fn x : int ⇒ 4) , s⟩

130
Full Beta – Semantics
Values
v ::= b | n | skip | (fn x : T ⇒ E)

SOS rules

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(beta-app1)
⟨E1 E2 , s⟩ −→ ⟨E1′ E2 , s′ ⟩

⟨E2 , s⟩ −→ ⟨E2′ , s′ ⟩
(beta-app2)
⟨E1 E2 , s⟩ −→ ⟨E1 E2′ , s′ ⟩

(beta-fn1) ⟨(fn x : T ⇒ E1 ) E2 , s⟩ −→ ⟨{E2 /x} E1 , s⟩

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(beta-fn2)
⟨(fn x : T ⇒ E) , s⟩ −→ ⟨(fn x : T ⇒ E ′ ) , s′ ⟩
131
Full Beta – Example

(fn x : int ⇒ x + x) (2 + 2)

(fn x : int ⇒ x + x) 4 (2 + 2) + (2 + 2)

4 + (2 + 2) (2 + 2) + 4

4+4

132
Choice 4: Normal-Order Reduction

Idea: leftmost, outermost variant of full beta.

133
Section 6

Typing for Call-By-Value

134
Typing Functions - TypeEnvironment

• so far Γ ranges over TypeEnv, the finite partial function from


L ⇀ Tloc
• with functions, it summarises assumptions on the types of variables
• type environments Γ are now pairs of a Γloc (L ⇀ Tloc )
and a Γvar , a partial function from X to T (X ⇀ T ).
For example, Γloc = {l1 : intref} and Γvar = {x : int, y : bool → int}.
• dom(Γ) = dom(Γloc ) ∪ dom(Γvar ).
• notation: if x ̸∈ dom(Γvar ), we write Γ, x : T , which adds x : T to
Γvar

135
Typing Functions

(var) Γ ⊢ x:T if Γ(x) = T

Γ, x : T ⊢ E : T ′
(fn)
Γ ⊢ (fn x : T ⇒ E) : T → T ′

Γ ⊢ E1 : T → T ′ Γ ⊢ E2 : T
(app)
Γ ⊢ E1 E2 : T ′

136
Typing Functions – Example I

( VAR ) ( INT )
x : int ⊢ x : int x : int ⊢ 2 : int
( OP+)
x : int ⊢ x + 2 : int
( FN ) ( INT )
{} ⊢ (fn x : int ⇒ x + 2) : int → int {} ⊢ 2 : int
( APP )
{} ⊢ (fn x : int ⇒ x + 2) 2 : int

137
Typing Functions – Example II

Determine the type of

(fn x : int → int ⇒ x (fn x : int ⇒ x) 3)

138
Properties Typing

We only consider closed programs, with no free variables.


Theorem (Progress)
If E closed, Γ ⊢ E : T and dom(Γ) ⊆ dom(s) then either E is a value or
there exist E ′ and s′ such that ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩.
There are more configurations that get stuck, e.g. (3 4).

Theorem (Type Preservation)


If E closed, Γ ⊢ E : T , dom(Γ) ⊆ dom(s) and ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ then
Γ ⊢ E ′ : T and dom(Γ) ⊆ dom(s′ ).

139
Proving Type Preservation

Theorem (Type Preservation)


If E closed, Γ ⊢ E : T , dom(Γ) ⊆ dom(s) and ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ then
Γ ⊢ E ′ : T and dom(Γ) ⊆ dom(s′ ).

Proof outline.
Choose

Φ(E, s, E ′ , s′ ) = ∀Γ, T. Γ ⊢ E : T ∧ closed(E) ∧ dom(Γ) ⊆ dom(s)


=⇒ Γ ⊢ E ′ : T ∧ closed(E ′ ) ∧ dom(Γ) ⊆ dom(s′ )


show ∀E, s, E ′ , s′ . ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ =⇒ Φ(E, s, E ′ , s′ ), by rule


induction ⊔

140
Proving Type Preservation – Auxiliary Lemma

Lemma (Substitution)
If E closed, Γ ⊢ E : T and Γ, x : T ⊢ E ′ : T ′ with x ̸∈ dom(Γ) then
Γ ⊢ {E/x} E ′ : T ′ .

141
Type Safety

Main result: Well-typed programs do not get stuck.


Theorem (Type Safety)
If Γ ⊢ E : T , dom(Γ) ⊆ dom(s), and ⟨E , s⟩ −→∗ ⟨E ′ , s′ ⟩ then either E ′ is
a value with Γ ⊢ E ′ : T , or there exist E ′′ , s′′ such that
⟨E ′ , s′ ⟩ −→ ⟨E ′′ , s′′ ⟩, Γ ⊢ E ′′ : T and dom(Γ) ⊆ dom(s′′ ).

Here, −→∗ means arbitrary many steps in the transition system.

142
Normalisation

Theorem (Normalisation)
In the sublanguage without while loops, if Γ ⊢ E : T and E closed then
there does not exist an infinite reduction sequence

⟨E , {}⟩ −→ ⟨E1 , {}⟩ −→ ⟨E2 , {}⟩ −→ . . .

Proof.
See B. Pierce, Types and Programming Languages, Chapter 12. ⊔

143
Section 7

Recursion

144
Scoping

Name Definitions
restrict the scope of variables

E ::= . . . | let val x : T = E1 in E2 end

• x is a binder for E2
• can be seen as syntactic sugar:

let val x : T = E1 in E2 end ≡ (fn x : T ⇒ E2 ) E1

145
Derived sos-rules and typing

let val x : T = E1 in E2 end ≡ (fn x : T ⇒ E2 ) E1

Γ ⊢ E1 : T Γ, x : T ⊢ E2 : T ′
(let)
Γ ⊢ let val x : T = E1 in E2 end : T ′

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(let1)
⟨let val x : T = E1 in E2 end , s⟩ −→ ⟨let val x : T = E1′ in E2 end , s′ ⟩

(let2) ⟨let val x : T = v in E2 end , s⟩ −→ ⟨{v/x} E2 , s⟩

146
Recursion – An Attempt
Consider
r = (fn y : int ⇒ if y ≥ 1 then y + (r (y + −1)) else 0)
where r is the recursive call (variable occurring in itself).
What is the evaluation of r 3?

We could try
E ::= . . . | let val rec x : T = E in E ′ end
where x is a binder for both E and E ′ .

let val rec r : int → int =


(fn y : int ⇒ if y ≥ 1 then y + (r (y + −1)) else 0)
in r 3 end

147
However . . .

• What about let val rec x : T = (x, x) in x end?


• What about let val rec x : int list = 3 :: x in x end?
Does this terminate? and if it does is it equal to
– let val rec x : int list = 3 :: 3 :: x in x end
• Does let val rec x : int list = 3 :: (x + 1) in x end terminate?
• In Call-by-Name (Call-by-Need) these are reasonable
• In Call-by-Value these would usually be disallowed

148
Recursive Functions

Idea specialise the previous let val rec


• T = T1 → T2 (recursion only at function types)
• E = (fn y : T1 ⇒ E1 ) (and only for function values)

149
Recursive Functions – Syntax and Typing

E ::= . . . | let val rec x : T1 → T2 = (fn y : T1 ⇒ E1 ) in E2 end


Here, y binds in E1 and x bind in (fn y : T1 ⇒ E1 ) and E2

Γ, x:T1 → T2 , y:T1 ⊢ E1 : T2 Γ, x:T1 → T2 ⊢ E2 : T


(recT)
Γ ⊢ let val rec x : T1 → T2 = (fn y : T1 ⇒ E1 ) in E2 end : T

150
Recursive Functions – Semantics

(rec) ⟨let val rec x : T1 → T2 = (fn y : T1 ⇒ E1 ) in E2 end , s⟩


−→
⟨{(fn y : T1 ⇒ let val rec x : T1 → T2 = (fn y : T1 ⇒ E1 ) in E1 end)/x} E2 , s⟩

151
Redundancies?
• Do we need E1 ; E2 ?
No: E1 ; E2 ≡ (fn y : unit ⇒ E2 ) E1

• Do we need while E1 do E2 ?
No:

while E1 do E2 ≡ let val rec w : unit → unit =


(fn y : unit ⇒ if E1 then (E2 ; (w skip)) else skip)
in
w skip
end

152
Redundancies?

• Do we need recursion?
Yes! Previously, normalisation theorem effectively showed that
while adds expressive power; now, recursion is even more powerful.

153
Side remarks I
• naive implementations (in particular substitutions) are inefficient
(more efficient implementations are shown in courses on compiler
construction)
• more concrete – closer to implementation or machine code – are
possible
• usually refinement to prove compiler to be correct
(e.g. CompCert or CakeML)

154
Side remarks I – CakeML

155
Side remarks II: Big-step Semantics
• we have seen a small-step semantics

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩

• alternatively, we could have looked at a big-step semantics

⟨E , s⟩ ⇓ ⟨E ′ , s′ ⟩

For example

⟨E1 , s⟩ ⇓ ⟨n1 , s′ ⟩ ⟨E2 , s′ ⟩ ⇓ ⟨n2 , s′′ ⟩


(n = n1 +n2 )
⟨n , s⟩ ⇓ ⟨n , s⟩ ⟨E1 + E2 , s⟩ ⇓ ⟨n , s′′ ⟩

• no major difference for sequential programs


• small-step much better for modelling concurrency and proving type
safety
156
Section 8

Data

157
Recap and Missing Steps

• simple while language


• with functions
• but no data structures

158
Products – Syntax

T ::= . . . | T ∗ T

E ::= . . . | (E, E) | fst E | snd E

159
Products – Typing

Γ ⊢ E1 : T1 Γ ⊢ E2 : T2
(pair)
Γ ⊢ (E1 , E2 ) : T1 ∗ T2

Γ ⊢ E : T1 ∗ T2
(proj1)
Γ ⊢ fst E : T1

Γ ⊢ E : T1 ∗ T2
(proj2)
Γ ⊢ snd E : T2

160
Products – Semantics
Values
v ::= . . . | (v, v)

SOS rules
⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(pair1)
⟨(E1 , E2 ) , s⟩ −→ ⟨(E1′ , E2 ) , s′ ⟩

⟨E2 , s⟩ −→ ⟨E2′ , s′ ⟩
(pair2)
⟨(v, E2 ) , s⟩ −→ ⟨(v, E2′ ) , s′ ⟩

(proj1) ⟨fst (v1 , v2 ) , s⟩ −→ ⟨v1 , s⟩ (proj2) ⟨snd (v1 , v2 ) , s⟩ −→ ⟨v2 , s⟩

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(proj3) (proj4)
⟨fst E , s⟩ −→ ⟨fst E ′ , s′ ⟩ ⟨snd E , s⟩ −→ ⟨snd E ′ , s′ ⟩

161
Sums (Variants, Tagged Unions) – Syntax

T ::= . . . | T + T

E ::= . . . | inl E : T | inr E : T |


case E of inl x1 : T1 ⇒ E | inr x2 : T2 ⇒ E

x1 and x2 are binders for E1 and E2 , up to alpha-equivalence

162
Sums – Typing I

Γ ⊢ E : T1
(inl)
Γ ⊢ inl E : T1 + T2 : T1 + T2

Γ ⊢ E : T2
(inr)
Γ ⊢ inr E : T1 + T2 : T1 + T2

Γ ⊢ E : T1 + T2 Γ, x : T1 ⊢ E1 : T Γ, y : T2 ⊢ E2 : T
(case)
Γ ⊢ case E of inl x : T1 ⇒ E1 | inr y : T2 ⇒ E2 : T

163
Sums – Typing II

case E of inl x : T1 ⇒ E1 | inr y : T2 ⇒ E2

Why do we need to carry around type annotations?


• maintain the unique typing property
Otherwise inl 3 : could be of type int + int or int + bool
• many programming languages allow type polymorphism

164
Sums – Semantics
Values
v ::= . . . | inl v : T | inr v : T

SOS rules
⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(inl) (inr)
⟨inl E : T , s⟩ −→ ⟨inl E ′ : T , s′ ⟩ ⟨inr E : T , s⟩ −→ ⟨inr E ′ : T , s′ ⟩

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(case1)
⟨case E of inl x : T1 ⇒ E1 | inr y : T2 ⇒ E2 , s⟩
−→ ⟨case E ′ of inl x : T1 ⇒ E1 | inr y : T2 ⇒ E2 , s′ ⟩
(case2) ⟨case inl v : T of inl x : T1 ⇒ E1 | inr y : T2 ⇒ E2 , s⟩
−→ ⟨{v/x} E1 , s⟩

(case3) ⟨case inr v : T of inl x : T1 ⇒ E1 | inr y : T2 ⇒ E2 , s⟩


−→ ⟨{v/y} E2 , s⟩

165
Constructors and Destructors

type constructors destructors


T →T (fn x : T ⇒ ) E

T ∗T (, ) fst snd

T +T inl : T inr : T case

bool true false if then else

166
Proofs as Programs

The Curry-Howard correspondence

(var) Γ, x : T ⊢ x : T Γ, P ⊢ P

Γ, x : T ⊢ E : T ′ Γ, P ⊢ P ′
(fn)
Γ ⊢ (fn x : T ⇒ E) : T → T ′ Γ ⊢ P → P′

Γ ⊢ E1 : T → T ′ Γ ⊢ E2 : T Γ ⊢ P → P′ Γ⊢P
(app) (modus ponens)
Γ ⊢ E1 E2 : T ′ Γ⊢P ′

...

167
Proofs as Programs: The Curry-Howard
correspondence

(var) Γ, x:T ⊢ x : T Γ, P ⊢ P

Γ, x:T ⊢ E : T ′ Γ, P ⊢ P ′
(fn)
Γ ⊢ (fn x : T ⇒ E) : T → T ′ Γ ⊢ P → P′

Γ ⊢ E1 : T → T ′ Γ ⊢ E2 : T Γ ⊢ P → P′ Γ⊢P
(app) (modus ponens)
Γ ⊢ E1 E2 : T ′ Γ ⊢ P′

Γ ⊢ E1 : T1 Γ ⊢ E2 : T2 Γ ⊢ P1 Γ ⊢ P2
(pair)
Γ ⊢ (E1 , E2 ) : T1 ∗ T2 Γ ⊢ P1 ∧ P2

Γ ⊢ E : T1 ∗ T2 Γ ⊢ E : T1 ∗ T2 Γ ⊢ P1 ∧ P2 Γ ⊢ P1 ∧ P2
(proj1) (proj2)
Γ ⊢ fst E : T1 Γ ⊢ snd E : T2 Γ ⊢ P1 Γ ⊢ P2

Γ ⊢ E : T1 Γ ⊢ E : T2 Γ ⊢ P1 Γ ⊢ P2
(inl) (inr)
Γ ⊢ inl E : T1 + T2 : T1 + T2 Γ ⊢ inr E : T1 + T2 : T1 + T2 Γ ⊢ P1 ∨ P2 Γ ⊢ P1 ∨ P2

Γ ⊢ E : T1 + T2 Γ, x : T1 ⊢ E1 : T Γ, y : T2 ⊢ E2 : T Γ ⊢ P1 ∨ P2 Γ, P1 ⊢ P Γ, P2 ⊢ P
(case)
Γ ⊢ case E of inl x : T1 ⇒ E1 | inr y : T2 ⇒ E2 : T Γ⊢P

(unit), (zero), . . . ; but not (letrec)

168
Curry-Howard correspondence (abstract)

Programming side Logic side


bottom type false formula
unit type true formula
sum type disjunction
product type conjunction
function type implication
generalised sum type (Σ type) existential quantification
generalised product type (Π type) universal quantification

169
Datatypes in Haskell
Datatypes in Haskell generalise both sums and products
data P a i r = P I n t Double
data E i t h e r = I I n t | D Double

The expression
data Expr = I n t V a l I n t
| BoolVal Bool
| P a i r V a l I n t Bool
is (roughly) like saying

Expr = int + bool + (int ∗ bool)

170
More Datatypes - Records

A generalisation of products.
Labels lab ∈ LAB for a set LAB = {p, q, ...}

T ::= . . . | {lab1 : T1 , . . . , labk : Tk }


E ::= . . . | {lab1 = E1 , . . . , labk = Ek } | #lab E

(where in each record (type or expression) no lab occurs more than


once)

171
Records – Typing

Γ ⊢ E1 : T1 ... Γ ⊢ Ek : Tk
(record)
Γ ⊢ {lab1 = E1 , . . . , labk = Ek } :{lab1 : T1 , . . . , labk : Tk }

Γ ⊢ E :{lab1 : T1 , . . . , labk : Tk }
(recordproj)
Γ ⊢ #labi E : Ti

172
Records – Semantics
Values
v ::= . . . | {lab1 = v1 , . . . , labk = vk }

SOS rules

⟨Ei , s⟩ −→ ⟨Ei′ , s′ ⟩
(record1)
⟨{lab1 = v1 , . . . , labi−1 = vi−1 , labi = Ei , . . . , labk = Ek } , s⟩
−→ ⟨{lab1 = v1 , . . . , labi−1 = vi−1 , labi = Ei′ , . . . , labk = Ek } , s′ ⟩

(record2) ⟨#labi {lab1 = v1 , . . . , labk = vk } , s⟩ −→ ⟨vi , s⟩

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(record3)
⟨#labi E , s⟩ −→ ⟨#labi E ′ , s′ ⟩

173
Mutable Store I

Most languages have some kind of mutable store.


Two main choices:

1. our approach
E ::= . . . | l := E | !l | x

▶ locations store mutable values


▶ variables refer to a previously calculated value – immutable
▶ explicit dereferencing and assignment
(fn x : int ⇒ l := (!l) + x)

174
Mutable Store II

Most languages have some kind of mutable store.


Two main choices:
2. languages as C or Java
▶ variables can refer to a previously calculated value
and overwrite that value
▶ implicit dereferencing
▶ some limited type machinery to limit mutability

void foo ( x : i n t ) {
l = l + x
...
}

175
References

T ::= . . . | T ref

Tloc ::= intref T ref

E ::= · · · | ll := E | !l
| E1 := E2 | !E | ref E | l

176
References – Typing

Γ ⊢ E :T
(ref)
Γ ⊢ ref E : T ref

Γ ⊢ E1 : T ref Γ ⊢ E2 : T
(assign)
Γ ⊢ E1 := E2 : unit

Γ ⊢ E : T ref
(deref)
Γ ⊢ !E : T

Γ(l) = T ref
(loc)
Γ ⊢ l : T ref

177
References – Semantics I

Values
A location is a value v ::= . . . | l
Stores s were finite partial functions L ⇀ Z.
We now take them to be finite partial functions from L to all values.

SOS rules

(ref1) ⟨ref v , s⟩ −→ ⟨l , s + {l 7→ v}⟩ if l ̸∈ dom(s)

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(ref2)
⟨ref E , s⟩ −→ ⟨ref E ′ , s′ ⟩

178
References – Semantics II
(deref1) ⟨!l , s⟩ −→ ⟨v , s⟩ if l ∈ dom(s) and s(l) = v

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(deref2)
⟨!E , s⟩ −→ ⟨!E ′ , s′ ⟩

(assign1) ⟨l := v , s⟩ −→ ⟨skip , s + {l 7→ v}⟩ if l ∈ dom(s)

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(assign2)
⟨l := E , s⟩ −→ ⟨l := E ′ , s′ ⟩

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(assign3)
⟨E := E2 , s⟩ −→ ⟨E ′ := E2 , s′ ⟩

179
Type Checking the Store

• so far we used dom(Γ) ⊆ dom(s) in theorems such as progress and


type preservation
• expressed ‘all locations in Γ exist in store s ’
• we need more
• for each l ∈ dom(s) we require that s(l) is typable
• moreover, s(l) might contain some other locations . . .

180
Type Checking – Example
Example

E = let val x : (int → int) ref = ref (fn z : int ⇒ z) in


(x := (fn z : int ⇒ if z ≥ 1 then z + ((!x) (z + −1)) else 0);
(!x) 3) end

which has reductions

⟨E , {}⟩

−→ ⟨E1 , {l1 7→ (fn z : int ⇒ z)⟩
−→∗ ⟨E2 , {l1 7→ (fn z : int ⇒ if z ≥ 1 then z + ((!l1 )(z + −1)) else 0)}⟩
−→∗ ⟨6 , . . . ⟩

181
Progress and Type Preservation

Definition (Well-type store)


Let Γ ⊢ s if dom(Γ) = dom(s) and if
∀l ∈ dom(s). Γ(l) = T ref =⇒ Γ ⊢ s(l) : T .

Theorem (Progress)
If E closed, Γ ⊢ E : T and Γ ⊢ s then either E is a value or there exist E ′
and s′ such that ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩.

Theorem (Type Preservation)


If E closed, Γ ⊢ E : T , Γ ⊢ s and ⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ then E ′ is closed
and for some Γ′ (with disjoint domain to Γ) Γ, Γ′ ⊢ E ′ : T and Γ, Γ′ ⊢ s′ .

182
Type Safety

Theorem (Type Safety)


If E closed, Γ ⊢ E : T , Γ ⊢ s, and ⟨E , s⟩ −→∗ ⟨E ′ , s′ ⟩ then either E ′ is a
value with Γ ⊢ E ′ : T , or there exist E ′′ , s′′ such that
⟨E ′ , s′ ⟩ −→ ⟨E ′′ , s′′ ⟩, and there exists a Γ′ s.t. Γ, Γ′ ⊢ E ′′ : T and
Γ, Γ′ ⊢ s′′ .

183
Section 9

Exceptions

184
Motivation
Trapped errors
Cause execution to halt immediately.
Examples: jumping to an illegal address, raising a top-level exception.
Innocuous?

Untrapped errors
May go unnoticed for a while and later cause arbitrary behaviour.
Examples: accessing data past the end of an array, security loopholes in
Java abstract machines.
Insidious!

program should signal error


• devision by zero

• index out of bound (e.g. • lookup key missing


record type) • file not found
• ...
185
Choice 1: Raising Exceptions

Idea: introduce term error that completely aborts an evaluation of


a term.

E ::= . . . | error

(no change of values nor types)

(err) Γ ⊢ error : T

186
Errors – Semantics

SOS rules

(apperr1) ⟨error E , s⟩ −→ ⟨error , s⟩

(apperr2) ⟨v error , s⟩ −→ ⟨error , s⟩

187
Errors

• (fn x : int ⇒ x) error →?


• let val rec x : int → int = (fn y : int ⇒ y) in x error end →?

• error can have arbitrary type, which violates type uniqueness


(can be fixed by subtyping)
• type preservation is maintained
• progress property needs adaptation (homework 2)

188
Choice 2: Handling Exceptions

Idea: install exception handlers (e.g. ML or Java)

E ::= . . . | try E with E

(no change of values nor types)

189
Handling Exceptions – Typing and Semantics
try E1 with E2 means ‘return result of evaluating E1 , unless it aborts, in
which case the handler E2 is evaluated’
Typing
Γ ⊢ E1 : T Γ ⊢ E2 : T
(try)
Γ ⊢ try E1 with E2 : T

SOS rules

(try1) ⟨try v with E , s⟩ −→ ⟨v , s⟩

(try2) ⟨try error with E , s⟩ −→ ⟨E , s⟩

⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(try3)
⟨try E1 with E2 , s⟩ −→ ⟨try E1′ with E2 , s′ ⟩

190
Choice 3: Exceptions with Values

Idea: inform user about type of error

E ::= . . . | error | raise E | try E with E

(no change of values)

191
Exceptions with Values – Typing

Typing
Γ ⊢ E : Tex
(try ex)
Γ ⊢ raise E : T

Γ ⊢ E1 : T Γ ⊢ E2 : Tex → T
(try v)
Γ ⊢ try E1 with E2 : T

192
Exceptions with Values – Semantics
SOS rules

(apprai1) ⟨(raise v) E , s⟩ −→ ⟨raise v , s⟩


(apprai2) ⟨v1 (raise v2 ) , s⟩ −→ ⟨raise v2 , s⟩

⟨E , s⟩ −→ ⟨E1′ , s′ ⟩
(rai)
⟨raise E , s⟩ −→ ⟨raise E ′ , s′ ⟩
(rai2) ⟨raise (raise v) , s⟩ −→ ⟨raise v , s⟩

(try1) ⟨try v with E , s⟩ −→ ⟨v , s⟩


(try2) ⟨try raise v with E , s⟩ −→ ⟨E v , s⟩
⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(try3)
⟨try E1 with E2 , s⟩ −→ ⟨try E1′ with E2 , s′ ⟩

193
The Type Tex (I)
• Tex = nat: corresponds to errno in Unix OSs;
0 indicates success; other values report various exceptional
conditions.
(similar in C++).
• Tex = string: avoids looking up error codes; more descriptive; error
handling may now require parsing a string
• Tex could be of type record

Tex ::= {dividedByZero : unit,


overflow : unit,
fileNotFound : string,
fileNotReadable : string,
...}

194
The Type Tex (II)

• ‘Tex in ML’: make records more flexible to allow fields to be added,


sometimes called extensible records or extensible variant type
• ‘Tex in Java’: use of classes, uses keyword throwable, which allows
the declaration of new errors. (We do not yet know what an object is)
• ...

195
Section 10

Subtyping

196
Motivation (I)

• so far we carried around types explicitly to avoid ambiguity of types


• programming languages use polymorphisms to allow different types
• some of it can be captured by subtyping
• common in all object-oriented languages
• subtyping is cross-cutting extension, interacting with most other
language features

197
Polymorphism

Ability to use expressions at many different types


• ad-hoc polymorphism (overloading),
e.g. + can be used to add two integers and two reals,
see Haskell type classes
• Parametric Polymorphism (e.g. ML or Isabelle)
write a function that for any type α takes an argument of type α list
and computes its length (parametric – uniform in whatever α is)
• Subtype polymorphism – as in various OO languages. See here.

198
Motivation (II)

Γ ⊢ E1 : T → T ′ Γ ⊢ E2 : T
(app)
Γ ⊢ E1 E2 : T ′

we cannot type

Γ ⊬ (fn x : {p : int} ⇒ #p x) {p = 3, q = 4} : int


Γ ⊬ (fn x : int ⇒ x) 3 : int (assuming 3 is of type nat)

even though the function gets a ‘better’ argument, with more structure

199
Subsumption
better: any term of type {p : int, q : int} can be used wherever a term of
type {p : int} is expected.

Introduce a subtyping relation between types


• T is a subtype of T ′ (a T is useful in more contexts than a T ′ )

T <: T ′

• should include {p : int, q : int} <: {p : int} <: {}


• introduce subsumption rule
Γ ⊢ E :T T <: T ′
(sub)
Γ ⊢ E :T′

200
Example

(var) (var) (var)


x : {p:int} ⊢ x :{p:int} {} ⊢ 3 : int {} ⊢ 4 : int
(recordproj) (record) {p:int, q:int} <: {p:int}
x : {p:int} ⊢ #p x : int {} ⊢ {p=3, q=4} :{p:int, q:int}
(fn) (sub)
{} ⊢ (fn x : {p:int} ⇒ #p x) :{p:int} → int {} ⊢ {p=3, q=4} :{p:int}
(app)
{} ⊢ (fn x : {p:int} ⇒ #p x) {p=3, q=4} : int

201
The Subtype Relation <:

(s-refl) T <: T

T <: T ′ T ′ <: T ′′
(s-trans)
T <: T ′′

the subtype order is not anti-symmetric – it is a preorder

202
Subtyping – Records

(s-rcd1) {lab1 :T1 , . . . , labk :Tk , labk+1 :Tk+1 , .., labk+n :Tk+n }
<: {lab1 :T1 , . . . , labk :Tk }

e.g. {p:int, q:int} <: {p:int}

T1 <: T1′ . . . Tk <: Tk′


(s-rcd2)
{lab1 :T1 , . . . , labk :Tk } <: {lab1 : T1′ , . . . , labk :Tk′ }

π a permutation of 1, . . . , k
(s-rcd3)
{lab1 :T1 , . . . , labk :Tk } <: {labπ(1) : Tπ(1) , . . . , labπ(k) :Tπ(k) }

203
Subtyping – Functions (I)

T1′ <: T1 T2 <: T2′


(s-fn)
T1 → T2 <: T1′ → T2′

• contravariant on the left of →


• covariant on the right of →

204
Subtyping – Functions (II)
If f : T1 → T2 then
– f can use any argument which is a subtype of T1 ;
– the result of f can be regarded as any supertype of T2

Example: let f = (fn x : {p:int} ⇒ {p=#p x, q=42})


we have

Γ ⊢ f :{p:int} → {p:int, q:int}


Γ ⊢ f :{p:int} → {p:int}
Γ ⊢ f :{p:int, q:int} → {p:int, q:int}
Γ ⊢ f :{p:int, q:int} → {p:int}

205
Subtyping – Functions (III)

Example: let f = (fn x : {p:int, q:int} ⇒ {p=(#p x) + (#q x)})

we have

Γ ⊢ f :{p:int, q:int} → {p:int}


Γ ⊬ f :{p:int} → T
Γ ⊬ f : T → {p:int, q:int}

206
Subtyping – Top and Bottom

(s-top) T <: Top

• not strictly necessary, but convenient


• corresponds to Object found in most OO languages

Does it make sense to have a bottom type Bot?


(see B. Pierce for an answer)

207
Subtyping – Products and Sums

Products

T1 <: T1′ T2 <: T2′


(s-pair)
T1 ∗ T2 <: T1′ ∗ T2′

Sums

Exercise

208
Subtyping – References (I)

Does one of the following make sense?


T <: T ′ T ′ <: T
T ref <: T ′ ref T ref <: T ′ ref

No

209
Subtyping – References (II)

T <: T ′ T ′ <: T
(s-ref)
T ref <: T ′ ref

• ref needs to be an invariant


• a more refined analysis of references is possible
(using Source – capability to read –, and Sink – capability to write)

Example:
{a:int, b:bool} ref <: {b:bool, a:int} ref

210
Typing – Remarks

Semantics
no change required (we did not change the grammar for expressions)

Properties
Type preservation, progress and type safety hold

Implementation
Type inference is more complicated; good run-time is also tricky due to
re-ordering

211
Down Casts
The rule (sub) permits up-casting. How down-casting?

E ::= . . . | (T ) E
Typing rule
Γ ⊢ E :T′
Γ ⊢ (T ) E : T

• requires dynamic type checking


(verify type safety of a program at runtime)
• gives flexibility, at the cost of potential run-time errors
• better handled by parametric polymorphism, a.k.a. generics (for
example Java)

212
Section 11

(Imperative) Objects
Case Study

213
Motivation

• use our language with subtyping, records and references to model


key keatures of OO programming
• encode/approximate concepts into our language
• OO concepts
▶ multiple representations (object carry their methods)
(in contrast to abstract data types (ADTs)
▶ encapsulation
▶ subtyping
interface is the set of names and types of its operations
▶ inheritance share common parts (class and subclasses)
some languages use delegations (e.g. C♯ ), which combine classes and
objects
▶ open recursion (self or this)

214
(Simple) Objects

• data structure encapsulating some internal state


• access via methods
• internal state typically a number of mutable instance variables (or
fields)
• attention lies on building, rather than usage

215
Reminder

Scope Restriction

E ::= . . . | let val x : T = E1 in E2 end

• x is a binder for E2
• can be seen as syntactic sugar:

let val x : T = E1 in E2 end ≡ (fn x : T ⇒ E2 ) E1

216
Objects – Example
A Counter Object
let val c : {get : unit → int, inc : unit → unit} =
let val x : int ref = ref 0 in
{get = (fn y : unit ⇒ !x),
inc = (fn y : unit ⇒ x := !x + 1)}
end
in
(#inc c)() ; (#get c)()
end

Counter = {get : unit → int, inc : unit → unit}

217
Objects – Example
Subtyping I
let val c : {get : unit → int, inc : unit → unit , reset : unit → unit} =
let val x : int ref = ref 0 in
{get = (fn y : unit ⇒ !x),
inc = (fn y : unit ⇒ x := !x + 1)}
reset = (fn y : unit ⇒ x := 0)}
end
in
(#inc c)() ; (#get c)()
end

ResCounter = {get : unit → int, inc : unit → unit, reset : unit → unit}

218
Objects – Example

Subtyping II

ResCounter <: Counter

219
Objects – Example
Object Generators

let val newCounter : unit → Counter =


(fn y : unit ⇒
let val x : int ref = ref 0 in
{get = (fn y : unit ⇒ !x),
inc = (fn y : unit ⇒ x := !x + 1)}
end)
in
(#inc (newCounter()))()
end

newRCounter defined in similar fashion

220
Simple Classes

• pull out common features


• ignore complex features
such as visibility annotations, static fields and methods, friend
classes . . .

• most primitive form, a class is a data structure that can


– be instantiated to yields a fresh object, or – extended to yield
another class

221
Reusing Method Code

Counter = {get : unit → int, inc : unit → unit}


CounterRep = {p : int ref}

222
(Simple) Classes

let val CounterClass : CounterRep → Counter =


(fn x : CounterRep ⇒
{get = (fn y : unit ⇒ !(#p x)),
inc = (fn y : unit ⇒ (#p x) := !(#p x) + 1)})

let val newCounter : unit → Counter =


(fn y : unit ⇒
let val x : CounterRep = {p = ref 0} in
CounterClass x
end)

223
IMP vs. Java

c l a s s Counter
{ protected i n t p ;
Counter ( ) { t h i s . p =0; }
i n t get ( ) { r e t u r n t h i s . p ; }
v o i d i n c ( ) { t h i s . p++ ; }
};

224
(Simple) Classes
(fn ResCounterClass : CounterRep → ResCounter ⇒
(fn x : CounterRep ⇒
let val super : Counter = CounterClass x in
{get = #get super,
inc = #inc super,
reset = (fn y : unit ⇒ (#p x) := 0)}
end))

CounterRep = {p : int ref}


Counter = {get : unit → int, inc : unit → unit}
ResCounter = {get : unit → int, inc : unit → unit, reset : unit → unit}

225
IMP vs. Java

c l a s s ResetCounter
extends Counter
{ v o i d r e s e t ( ) { t h i s . p =0;}
};

226
(Simple) Classes

BuCounter = {get : unit → int, inc : unit → unit,


reset : unit → unit, backup : unit → unit}
BuCounterRep = {p : int ref, b : int ref}

let val BuCounterClass : BuCounterRep → BuCounter =


(fn x : BuCounterRep ⇒
let val super : ResCounter = ResCounterClass x in
{get = #get super, inc = #inc super,
reset = (fn y : unit ⇒ (#p x) := !(#b x))}
backup = (fn y : unit ⇒ (#b x) := !(#p x))}
end)
227
Section 12

Implementing IMP

228
Motivation

• started with (a variant) of IMP


• added several features
(e.g. functions, exceptions, objects, . . . )
• no concurrency yet
• no verification
(you may have seen some bits of Hoare logic)

229
Implementations of IMP I

• ML
https://www.cl.cam.ac.uk/teaching/2021/Semantics/L2/
P. Sewell
• C
“any compiler”
• Java
https://www.cl.cam.ac.uk/teaching/2021/Semantics/L1/l1.java
M. Parkinson
• Haskell
(several implementations available)

230
Implementations of IMP II

• Coq
https://softwarefoundations.cis.upenn.edu/lf-current/Imp.html
B. Pierce
• Isabelle
https://isabelle.in.tum.de (src/HOL/IMP)
G. Klein and T. Nipkow

231
Section 13

IMP in Isabelle/HOL

232
Motivation/Disclaimer

• generic proof assistant


• express mathematical formulas in a formal language
• tools for proving those formulas in a logical calculus
• originally developed at the University of Cambridge
and Technische Universität München
(now numerous contributions, including Australia)

• this is neither a course about Isabelle nor a proper


introduction to Isabelle

233
Isabelle/HOL – Introduction

Isabelle/HOL = Functional Programming + Logic


Isabelle HOL has
• datatypes
• recursive functions
• logical operators
• ...

Isabelle/HOL is a programming language, too


• Higher-order means that functions are values, too

234
Isabelle/HOL – Terms (Expressions)
• Functions
▶ application: f E
call of function f with parameter E
▶ abstraction: λx. E
function with parameter x (of some type) and result E ((fn x : T? ⇒ t))
▶ Convention (as always) f E1 E2 E3 ≡ ((f E1 ) E2 ) E3

• Basic syntax (Isabelle)


t ::= (t)
| a identifier (constant or variable)
| tt function application
| λx. t function abstraction
| ... syntactic sugar

• Substitution notation: t[u/x]

235
Isabelle/HOL – Types I
• Basic syntax (Isabelle)
τ ::= (τ )
| bool | int | string | . . . base types

| a | ′b | . . . type variables
| τ ⇒τ functions
| τ ×τ pairs
| τ list lists
| τ set sets
| ... user-defined types
Convention: τ1 ⇒ τ2 ⇒ τ3 ≡ τ1 ⇒ (τ2 ⇒ τ3 )
• Terms must be well-typed; in particular
t :: τ1 ⇒ τ2 u :: τ1
t u :: τ2

236
Isabelle/HOL – Types II
Type inference
• automatic

• function overloading possible


can prevent type inference
• type annotation t :: τ (for example f (x :: int)

Currying
• curried vs. tupled

f τ1 ⇒ τ2 ⇒ τ3 vs f τ1 × τ2 ⇒ τ3

• use curried versions if possible


• advantage: allow partial function application

f a1 where a1 :: τ1

237
Isabelle (Cheatsheet I)

Isabelle module = Theory (File structure)

Syntax: theory M yT h
imports T h1 , . . . , T hn
begin
(definitions, lemmas, theorems, proofs, . . . )∗
end

M yT h: name of theory. Must live in file M yT h.thy


T hi : names of imported theories; imports are transitive

Usually: imports Main

238
IMP – Syntax (recap)
Booleans b ∈ B = {true, false}
Integers (Values) n ∈ Z = {. . . , −1, 0, 1, . . . }
Locations l ∈ L = {l, l0 , l1 , l2 , . . . }
Operations op ::= + | ≥
Expressions
E ::= n | b | E op E |
l := E | !l |
if E then E else E |
skip | E ; E |
whileE do E

239
IMP – Syntax (aexp and bexp)
Booleans b∈B
Integers (Values) n∈Z
Locations l ∈ L = {l, l0 , l1 , l2 , . . . }
Operations aop ::= +
Expressions
aexp ::= n | !l | aexp aop aexp
bexp ::= b | bexp ∧ bexp | aexp ≥ aexp
com ::= n | b | E op E |
l ::= aexp | !l |
IF bexp THEN com ELSE com |
SKIP | com ;; com |
WHILE bexp DO com

240
IMP – Syntax (Isabelle)
Booleans bool
Integers (Values) int
Locations string
Expressions
datatype aexp ::= N int | L loc | Plus aexp aexp
datatype bexp ::= B bool | Geq aexp aexp
datatype com ::= Assign loc aexp |
If bexp com com |
SKIP | Seq com com |
WHile bexp com

241
IMP – Syntax (Isabelle)

LINK: /src/HOL/IMP

242
Isabelle (Cheatsheet II)

type synonym specify synonym for a type


datatype define recursive (polymorphic) types
fun define (simple, recursive) function
(tries to prove exhaustiveness, non-overlappedness, and termination)
value evaluate a term

243
Small-step semantics

• a configuration ⟨E , s⟩ can perform a step if there is a derivation tree


• vice versa the set of all transitions can be defined inductively
• it is an infinite set

244
IMP Semantics
(deref) ⟨!l , s⟩ −→ ⟨n , s⟩ if l ∈ dom(s) and s(l) = n
(assign1) ⟨l := n , s⟩ −→ ⟨skip , s + {l 7→ n}⟩ if l ∈ dom(s)
⟨E , s⟩ −→ ⟨E ′ , s′ ⟩
(assign2)
⟨l := E , s⟩ −→ ⟨l := E ′ , s′ ⟩
(seq1) ⟨skip; E2 , s⟩ −→ ⟨E2 , s⟩
⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(seq2)
⟨E1 ; E2 , s⟩ −→ ⟨E1 ; E2 , s⟩
(if1) ⟨if true then E2 else E3 , s⟩ −→ ⟨E2 , s⟩
(if2) ⟨if false then E2 else E3 , s⟩ −→ ⟨E3 , s⟩
⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(if3)
⟨if E1 then E2 else E3 , s⟩ −→ ⟨if E1′ then E2 else E3 , s′ ⟩
(while) ⟨whileE1 do E2 , s⟩ −→ ⟨if E1 then (E2 ; whileE1 do E2 ) then skip , s⟩

245
IMP Semantics

(assign1) ⟨l := n , s⟩ −→ ⟨skip , s + {l 7→ n}⟩ if l ∈ dom(s)


(seq1) ⟨skip; E2 , s⟩ −→ ⟨E2 , s⟩
⟨E1 , s⟩ −→ ⟨E1′ , s′ ⟩
(seq2)
⟨E1 ; E2 , s⟩ −→ ⟨E1 ; E2 , s⟩
(if1) ⟨if true then E2 else E3 , s⟩ −→ ⟨E2 , s⟩
(if2) ⟨if false then E2 else E3 , s⟩ −→ ⟨E3 , s⟩
(while) ⟨whileE1 do E2 , s⟩ −→ ⟨if E1 then (E2 ; whileE1 do E2 ) then skip , s⟩

246
IMP Semantics (Isabelle)

LINK: /src/HOL/IMP/Small Step

247
IMP – Examples

• If E = (l2 := 0; while !l1 ≥ 1 do (l2 := !l2 + !l1 ; l1 := !l1 + −1))


s = {l1 7→ 3, l2 7→ 0}
then ⟨E , s⟩ −→∗ ?
• determinacy
• progress

248
Isabelle (Cheatsheet III)

inductive defines (smallest) inductive set


print theorems shows generated theorems
find theorems searches available theorems
by name and/or pattern
apply (<rule/tactic>) applies rule to proof goal
(simp, auto, blast, rule <name>)

249
Big-step semantics
(in Isabelle/HOL)

250
Another View: Big-step Semantics
• we have seen a small-step semantics

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩

• alternatively, we could have looked at a big-step semantics

⟨E , s⟩ ⇓ ⟨E ′ , s′ ⟩

For example

⟨E1 , s⟩ ⇓ ⟨n1 , s′ ⟩ ⟨E2 , s′ ⟩ ⇓ ⟨n2 , s′′ ⟩


(n = n1 +n2 )
⟨n , s⟩ ⇓ ⟨n , s⟩ ⟨E1 + E2 , s⟩ ⇓ ⟨n , s′′ ⟩

• no major difference for sequential programs


• small-step much better for modelling concurrency

251
Final State

• Isabelle’s version of IMP has only one value: SKIP


• big-step semantics can be seen as relation

⟨E , s⟩ =⇒ s′

252
Semantics
(Skip) ⟨SKIP , s⟩ =⇒ s

(Assign) ⟨l := a , s⟩ =⇒ s + {l 7→ aval a s)
⟨E1 , s⟩ =⇒ s′ ⟨E2 , s′ ⟩ =⇒ s′′
(Seq)
⟨E1 ; E2 , s⟩ =⇒ s′′
bval b s = true ⟨E1 , s⟩ =⇒ s′
(IfT)
⟨if b then E1 else E2 , s⟩ =⇒ s′
bval b s = false ⟨E2 , s⟩ =⇒ s′
(IfF)
⟨if b then E1 else E2 , s⟩ =⇒ s′
bval b s = false
(WhileF)
⟨while b do E , s⟩ =⇒ s
bval b s = true ⟨E , s⟩ =⇒ s′ ⟨while b do E , s′ ⟩ =⇒ s′′
(WhileT)
⟨while b do E , s⟩ =⇒ s′′

253
IMP Semantics (Isabelle)

LINK: /src/HOL/IMP/Big Step

• inversion rules
• induction set up
• see Nipkow/Klein for more details and explanation

254
Are big and small-step semantics equivalent?

255
Isabelle (Cheatsheet IV)

Proof Styles/Proof ‘Tactics’

apply-style apply rules (backwards)


ISAR human readable proofs
slegdehammer the ‘secret’ weapon
incorporating automated theorem provers

256
From Big to Small

Theorem
If cs ⇒ s′ then cs −→∗ ⟨SKIP , s′ ⟩.
Proof by rule induction (on cs ⇒ s′ ).

In two cases a lemma is needed.


Lemma
If ⟨E , s⟩ −→∗ ⟨E ′ , s′ ⟩ then ⟨E ; E2 , s⟩ −→∗ ⟨E ′ ; E2 , s′ ⟩.
Proof by rule induction.
(generalisation of (seq2))

257
From Small to Big

Theorem
If cs −→∗ ⟨SKIP , s′ ⟩ then cs ⇒ s′ .
Proof by rule induction (on cs −→∗ ⟨SKIP , s′ ⟩).

The induction step needs the following (interesting) lemma.


Lemma
If cs −→ cs′ and cs′ ⇒ s then cs ⇒ s.
Proof by rule induction on cs −→ cs′ .

258
Equivalence

Corollary
cs −→∗ ⟨SKIP , s′ ⟩ if and only if cs ⇒ s′ .

LINK: /src/HOL/Small Step

259
But are they really equivalent?
• What about premature termination?
• What about (non) termination?

Lemma
1. final ⟨E , s⟩ if and only if E = SKIP.
2. ∃s. cs ⇒ s if and only if ∃cs′ . cs −→∗ cs′ ∧ final cs′ .
where final cs ≡ (¬∃cs′ . cs → cs′ )

Proof.
1. induction and rule inversion
2. (∃s. cs ⇒ s) ⇔ ∃s. cs −→∗ ⟨SKIP , s⟩ (by big = small)
⇔ ∃cs′ . cs −→∗ cs′ ∧ final cs′ (by final = SKIP)

260
Typing
(almost straight-forward)
LINK: /src/HOL/Types
inductive btyping :: ''tyenv ⇒ bexp ⇒ bool''(infix ''⊢''50)
where
B ty:''Γ ⊢ Bc v'' |
Not ty:''Γ ⊢ b =⇒ Γ ⊢ Not b'' |
And ty:''Γ ⊢ b1 =⇒ Γ ⊢ b2 =⇒ Γ ⊢ And b1 b2'' |
Less ty:''Γ ⊢ a1 : τ =⇒ Γ ⊢ a2 : τ =⇒ Γ ⊢ Less a1 a2''

inductive ctyping ::''tyenv ⇒ com ⇒ bool''(infix '' ⊢ ''50)


where
Skip ty:''Γ ⊢ SKIP'' |
Assign ty:''Γ ⊢ a : Γ(x) =⇒ Γ ⊢ x ::= a'' |
Seq ty:''Γ ⊢ c1 =⇒ Γ ⊢ c2 =⇒ Γ ⊢ c1 ; ; c2'' |
If ty:''Γ ⊢ b =⇒ Γ ⊢ c1 =⇒ Γ ⊢ c2 =⇒ Γ ⊢ IF b THEN c1 ELSE c2'' |
While ty:''Γ ⊢ b =⇒ Γ ⊢ c =⇒ Γ ⊢ WHILE b DO c''

261
Section 14

Semantic Equivalence

262
Operational Semantics (Reminder)
• describe how to evaluate programs
• a valid program is interpreted as sequences of steps
• small-step semantics
▶ individual steps of a computation
▶ more rules (compared to big-step)
▶ allows to reason about non-terminating programs, concurrency, . . .
• big-step semantics
▶ overall results of the executions
‘divide-and-conquer manner’
▶ can be seen as relations
▶ fewer rules, simpler proofs
▶ no non-terminating behaviour
• allow non-determinism

263
Motivation CakeML

When are two programs considered the ‘same’

• compiler construction
• program optimisation
• refinement
• ...

264
Equivalence: Intuition I

? ?
l :=!l + 2 ≃ l :=!l + (1 + 1) ≃ l :=!l + 1 ; l :=!l + 1

• are these expressions the same


• in what sense
▶ different abstract syntax trees
▶ different reduction sequences
• in any (sequential) program one could replace one by the other
without affecting the result

Note: mathematicians often take these equivalences for granted

265
Equivalence: Intuition II
?
l := 0 ; 4 ≃ l := 1 ; 3 +!l

• produce same result (for all stores)


• cannot be replaced in an arbitrary context C

For example, let C[ ] = + !l

C[l := 0 ; 4] = (l := 0 ; 4) +!l

̸≃
C[l := 1 ; 3 +!l] = (l := 1 ; 3 + !l) +!l

On the other hand (l :=!l + 2) ≃ (l :=!l + 1 ; l :=!l + 1)

266
Equivalence: Intuition III

From particular expressions to general laws


?
• E1 ; (E2 ; E3 ) ≃ (E1 ; E2 ) ; E3
?
• (if E1 then E2 else E3 ) ; E ≃ if E1 then E2 ; E else E3 ; E
?
• E ; (if E1 then E2 else E3 ) ≃ if E1 then E ; E2 else E ; E3
?
• E ; (if E1 then E2 else E3 ) ≃ if E ; E1 then E2 else E3

267
Exercise

let val x : int ref = ref 0 in (fn y : int ⇒ (x :=!x + y) ;!x) end
?

let val x : int ref = ref 0 in (fn y : int ⇒ (x :=!x − y) ; (0 −!x)) end

268
Exercise II

Extend our language with location equality

op := . . . | =

Γ ⊢ E1 : T ref Γ ⊢ E2 : T ref
(op =)
Γ ⊢ E1 = E2 : bool

(op=1) ⟨l = l′ , s⟩ −→ ⟨b , s⟩ if b = (l = l′ )

(op=2) ...

269
Exercise II
?
f ≃g
for

f = let val x : int ref = ref 0 in


let val y : int ref = ref 0 in
(fn z : int ref ⇒ if z = x then y else x)
end end

and

g = let val x : int ref = ref 0 in


let val y : int ref = ref 0 in
(fn z : int ref ⇒ if z = y then y else x)
end end

270
Exercise II (cont’d)
?
f ≃g NO

Consider C[ ] = t with

t = (fn h : (int ref → int ref) ⇒


let val z : int ref = ref 0 in h (h z) = h z end)

⟨t f , s⟩ −→∗ ?
⟨t g , s⟩ −→∗ ?

271
A ‘good’ notion of semantic equivalence

We might
• understand what a program is
• prove that some particular expressions to be equivalent
(e.g. efficient algorithm vs. clear specification)
• prove the soundness of general laws for equational reasoning about
programs
• prove some compiler optimisations are sound (see CakeML or
CertiCos)
• understand the differences between languages

272
What does ‘good’ mean?

1. programs that result in observably-different values (for some store)


must not be equivalent

(∃s, s1 , s2 , v1 , v2 .
⟨E1 , s⟩ −→∗ ⟨v1 , s1 ⟩ ∧
⟨E2 , s⟩ −→∗ ⟨v2 , s2 ⟩ ∧
v1 ̸= v2 )
⇒ E1 ̸≃ E2

2. programs that terminate must not be equivalent to programs that do


not terminate

273
What does ‘good’ mean?
3. ≃ must be an equivalence relation, i.e.
reflexivity E≃E
symmetry E1 ≃ E2 ⇒ E2 ≃ E1
transitivity E1 ≃ E2 ∧ E2 ≃ E3 ⇒ E1 ≃ E3

4. ≃ must be a congruence, i.e,


if E1 ≃ E2 then for any context C we must have C[E1 ] ≃ C[E2 ]

(for example, (E1 ≃ E2 ) ⇒ (E1 ; E ≃ E2 ; E))

5. ≃ should relate as many programs as possible

– an equivalence relation that is a congruence is sometimes called congruence relation


– this semantic equivalence, is called observable operational or contextual equivalence
– congruence proofs are often tedious, and incredible hard when it comes to recursion

274
Semantic Equivalence for (simple) Typed IMP

Definition
E1 ≃TΓ E2 iff for all stores s with dom(Γ) ⊆ dom(s) we have

Γ ⊢ E1 : T and Γ ⊢ E2 : T ,

and either
(i) ⟨E1 , s⟩ −→ω and ⟨E2 , s⟩ −→ω , or
(ii) for some v, s′ we have ⟨E1 , s⟩ −→∗ ⟨v , s′ ⟩ and ⟨E2 , s⟩ −→∗ ⟨v , s′ ⟩.

−→ω : infinite sequence


−→∗ : finite sequence (reflexive transitive closure)

275
Justification

Part (ii) requires same value v and same store s′ . If a program generates
different stores, we can distinguish them using contexts:
• If T = unit then C[ ] = ;!l
• If T = bool then C[ ] = if then !l else !l
• If T = int then C[ ] = (l1 := ;!l)

276
Equivalence Relation

Theorem
The relation ≃TΓ is an equivalence relation.

Proof.
trivial ⊔

277
Congruence for (simple) Typed IMP
contexts are:

C[ ] ::= op E2 | E1 op |
if then E2 else E3 |
if E1 then else E3 |
if E1 then E2 else |
l := |
; E2 | E1 ;
while do E2 | while E1 do
Definition
The relation ≃TΓ has the congruence property if, for all E1 and E2 ,
whenever E1 ≃TΓ E2 we have for all C and T ′ , if Γ ⊢ C[E1 ] : T ′ and
Γ ⊢ C[E2 ] : T ′ then

C[E1 ] ≃TΓ C[E2 ]

278
Congruence Property
Theorem (Congruence for (simple) typed IMP)
The relation ≃TΓ has the congruence property.

Proof.
By case distinction, considering all contexts C. ⊔

For each context C (and arbitrary expression E and store s) consider the
possible reduction sequence

⟨C[E] , s⟩ −→ ⟨E1 , s1 ⟩ −→ ⟨E2 , s2 ⟩ −→ . . .

and deduce the behaviour of E:

⟨E , s⟩ −→ ⟨Ê1 , s1 ⟩ −→ . . .

Use E ≃TΓ E ′ find a similar reduction sequence of E ′ and use the


reduction rules to construct a sequence of C[E ′ ].
279
Proof of Congruence Property

Case C = (l := )
Suppose E ≃TΓ E ′ , Γ ⊢ l := E : T ′ and Γ ⊢ l := E ′ : T ′ .
By examination of the typing rule, we have T = int and T ′ = unit.

To show (l := E) ≃TΓ (l := E ′ ) we have to show that for all stores s if
dom(Γ) ⊆ dom(s) then
• Γ ⊢ l := E : T ′ , (obvious)
• Γ ⊢ l := E ′ : T ′ ,(obvious)
• and either
(i) ⟨l := E , s⟩ −→ω and ⟨l := E ′ , s⟩ −→ω
(ii) for some v, s′ we have ⟨l := E , s⟩ −→∗ ⟨v , s′ ⟩ and
⟨l := E ′ , s⟩ −→∗ ⟨v , s′ ⟩.

280
Proof of Congruence Property
Subcase ⟨l := E , s⟩ −→ω
That is
⟨l := E , s⟩ −→ ⟨E1 , s1 ⟩ −→ ⟨E2 , s2 ⟩ −→ . . .
All these must be instances of Rule (assign2), with

⟨E , s⟩ −→ ⟨Ê1 , s1 ⟩ −→ ⟨Ê2 , s2 ⟩ −→ . . .

and E1 = (l := Ê1 ), E2 = (l := Ê2 ), . . .


By E ≃TΓ E ′ there is an infinite reduction sequence of ⟨E ′ , s⟩.
Using Rule (assign2) there is an infinite reduction sequence of
⟨l := E ′ , s⟩.

We made the proof simple by staying in a deterministic language with


unique derivation trees.

281
Proof of Congruence Property

Subcase ¬(⟨l := E , s⟩ −→ω )


That is

⟨l := E , s⟩ −→ ⟨E1 , s1 ⟩ −→ ⟨E2 , s2 ⟩ −→ . . . −→ ⟨Ek , sk ⟩ ̸−→

All these must be instances of Rule (assign2), except the last step which
is an instance of (assign1)

⟨E , s⟩ −→ ⟨Ê1 , s1 ⟩ −→ ⟨Ê2 , s2 ⟩ −→ . . . −→ ⟨Êk−1 , sk−1 ⟩

and E1 = (l := Ê1 ), E2 = (l := Ê2 ), . . . , Ek−1 = (l := Êk−1 ) and


Êk−1 = n, Ek = skip and sk = sk−1 + {l 7→ n}, for some n.

282
Proof of Congruence Property

Subcase ¬(⟨l := E , s⟩ −→ω ) (cont’d)


Hence there is some n and sk−1 such that

⟨E , s⟩ −→∗ ⟨n , sk−1 ⟩ and ⟨l := E , s⟩ −→ ⟨skip , sk−1 + {l 7→ n}⟩ .

By E ≃TΓ E ′ we have ⟨E ′ , s⟩ −→∗ ⟨n , sk−1 ⟩.


Using Rules (assign2) and (assign1)

⟨l := E ′ , s⟩ −→∗ ⟨l := n , sk−1 ⟩ → ⟨skip , sk−1 + {l 7→ n}⟩ .

283
Congruence Proofs

Congruence proofs are


• tedious
• long
• mostly boring (up to the point where they brake)
• error prone
• recursion is often the killer case

There are dozens of different semantic equivalences


(and each requires a proof)

284
Back to Examples

• 1 + 1 ≃int
Γ 2 for any Γ

• (l := 0 ; 4) ̸≃int
Γ (l := 1 ; 3 + !l) for any Γ

• (l :=!l + 1) ; (l :=!l + 1) ≃unit


Γ (l :=!l + 2) for any Γ including l : intref

285
General Laws
Conjecture
E1 ; (E2 ; E3 ) ≃TΓ (E1 ; E2 ) ; E3
for any Γ, T , E1 , E2 and E3 such that Γ ⊢ E1 : unit, Γ ⊢ E2 : unit and
Γ ⊢ E3 : T .

Conjecture
((if E1 then E2 else E3 ) ; E) ≃TΓ (if E1 then E2 ; E else E3 ; E)
for any Γ, T , E, E1 , E2 and E3 such that Γ ⊢ E1 : bool, Γ ⊢ E2 : unit,
Γ ⊢ E3 : unit, and Γ ⊢ E : T .

Conjecture
(E ; (if E1 then E2 else E3 )) ̸≃TΓ (if E1 then E ; E2 else E ; E3 )

286
General Laws

Suppose Γ ⊢ E1 : unit and Γ ⊢ E2 : unit.


When is E1 ; E2 ≃unit
Γ E2 ; E1 ?

287
A Philosophical Question
What is a typed expression Γ ⊢ E : T ?

for example l : intref ⊢ if !l ≥ 0 then skip else (skip ; l := 0) : unit.

1. a list of tokens (after parsing) [IF, DEREF, LOC "l", GTEQ, ...]
2. an abstract syntax tree
3. the function taking store s to the reduction sequence

⟨E , s⟩ −→ ⟨E1 , s1 ⟩ −→ ⟨E2 , s2 ⟩ −→ . . .

4. the equivalence class {E ′ | E ≃TΓ E ′ }


5. the partial function [[E]]Γ that takes any store s with
dom(s) = dom(Γ) and either is undefined if ⟨E , s⟩ −→ω , or is
⟨v , s′ ⟩, if ⟨E , s⟩ −→∗ ⟨v , s′ ⟩

288
Section 15

Denotational Semantics

289
Operational Semantics (Reminder)
• describe how to evaluate programs
• a valid program is interpreted as sequences of steps
• small-step semantics
▶ individual steps of a computation
▶ more rules (compared to big-step)
▶ allows to reason about non-terminating programs, concurrency, . . .
• big-step semantics
▶ overall results of the executions
‘divide-and-conquer manner’
▶ can be seen as relations
▶ fewer rules, simpler proofs
▶ no non-terminating behaviour
• allow non-determinism

290
Operational vs Denotational

An operational semantics is like an interpreter

⟨E , s⟩ −→ ⟨E ′ , s′ ⟩ and ⟨E , s⟩ ⇓ ⟨v , s′ ⟩

A denotational semantics is like a compiler.


A denotational semantics defines what a program means as a (partial)
function:
C[[com]] ∈ Store ⇀ Store
Allows the use of ‘standard’ mathematics

291
Big Picture

op. sem denot. sem


[[ ]]≃T
Γ

NForm E/ ≃TΓ Semantics

292
IMP – Syntax (aexp and bexp)
Booleans b∈B
Integers (Values) n∈Z
Locations l ∈ L = {l, l0 , l1 , l2 , . . . }
Operations aop ::= +
Expressions
aexp ::= n |!l | aexp aop aexp
bexp ::= b | bexp ∧ bexp | aexp ≥ aexp
com ::= l := aexp |
if bexp then com else com |
skip | com ; com |
while bexp do com

293
Semantic Domains

C[[c]] ∈ Store ⇀ Store C[[ ]] : com → Store ⇀ Store

A[[a]] ∈ Store ⇀ int A[[ ]] : aexp → Store ⇀ int

B[[b]] ∈ Store ⇀ bool B[[ ]] : bexp → Store ⇀ bool

Convention: (Partial) Functions are defined point-wise.


C[[ ]] is the denotation function.

294
Partial Functions

Remember that partial functions can be represented as sets.


• C[[c]] can be described as a set
• the equation C[[c]] = S,
for a set S gives the definition for command c
• C[[c]](s) is a store

295
Denotational Semantics for IMP
Arithmetic Expressions

A[[n]] = {(s, n)}

A[[!l]] = {(s, s(l)) | l ∈ dom(s)}

A[[a1 + a2 ]] = {(s, n) | (s, n1 ) ∈ A[[a1 ]] ∧ (s, n2 ) ∈ A[[a2 ]] ∧ n = n1 + n2 }

n is syntactical, n semantical value.

296
Denotational Semantics for IMP
Boolean Expressions

B[[true]] = {(s, true)}

B[[false]] = {(s, false)}

B[[b1 ∧ b2 ]] = {(s, b) | (s, b′ ) ∈ B[[b1 ]] ∧ (s, b′′ ) ∈ B[[b2 ]] ∧ (b = b′ ∧ b′′ )}

B[[a1 ≥ a2 ]] = {(s, true) | (s, n1 ) ∈ A[[a1 ]] ∧ (s, n2 ) ∈ A[[a2 ]] ∧ n1 ≥ n2 } ∪


{(s, false) | (s, n1 ) ∈ A[[a1 ]] ∧ (s, n2 ) ∈ A[[a2 ]] ∧ n1 < n2 }

297
Denotational Semantics for IMP
Arithmetic and Boolean Expressions in Function-Style

A[[n]](s) = n
A[[!l]](s) = s(l) if l ∈ dom(s)
A[[a1 + a2 ]](s) = A[[a1 ]](s) + A[[a2 ]](s)

B[[true]](s) = true
B[[false]](s) = false
B[[a1 ∧ a2 ]](s) = B[[b1 ]](s) ∧ B[[b2 ]](s)

true if A[[a1 ]](s) ≥ A[[a2 ]](s)
B[[b1 ≥ a2 ]](s) =
false otherwise

298
Denotational Semantics for IMP
Commands

C[[skip]] = {(s, s)}

C[[l := a]] = {(s, s + {l 7→ n}) | (s, n) ∈ A[[a]]}

C[[c1 ; c2 ]] = {(s, s′′ ) | ∃s′ . (s, s′ ) ∈ C[[c1 ]] ∧ (s′ , s′′ ) ∈ C[[c2 ]]}

C[[if b then c1 else c2 ]] = {(s, s′ ) | (s, true) ∈ B[[b]] ∧ (s, s′ ) ∈ C[[c1 ]]} ∪
{(s, s′ ) | (s, false) ∈ B[[b]] ∧ (s, s′ ) ∈ C[[c2 ]]}

299
Denotational Semantics for IMP
Commands in Function-Style

C[[skip]](s) = s

C[[l := a]](s) = s + {l 7→ (A[[a]](s))}

C[[c1 ; c2 ]] = C[[c2 ]] ◦ C[[c1 ]]


(or C[[c1 ; c2 ]](s) = C[[c2 ]](C[[c1 ]](s)) )

C[[c1 ]](s) if B[[b]](s) = true
C[[if b then c1 else c2 ]](s) =
C[[c2 ]](s) if B[[b]](s) = false

denotational semantics is often compositional


300
Denotational Semantics for IMP
Commands
(cont’d)

C[[while b do c]] = {(s, s) | (s, false) ∈ B[[b]]} ∪


{(s, s′ ) | (s, true) ∈ B[[b]] ∧
∃s′′ . (s, s′′ ) ∈ C[[c]] ∧ (s′′ , s′ ) ∈ C[[while b do c]]}

C[[while b do c]](s) = C[[if b then c ; (while b do c) else skip]](s)



C[[while b do c]](C[[c]](s)) if B[[b]](s) = true
=
C[[skip]](s) if B[[b]](s) = false

Problem: this is not a function definition;


it is a recursive equation, we require its solution

301
Recursive Equations – Example


0 if x = 0
f (x) =
f (x − 1) + 2x − 1 otherwise

Question: What function(s) satisfy this equation?


Answer: f (x) = x2

302
Recursive Equations – Example II

g(x) = g(x) + 1

Question: What function(s) satisfy this equation?


Answer: none

303
Recursive Equations – Example III

x
h(x) = 4 · h
2

Question: What function(s) satisfy this equation?


Answer: multiple

304
Solving Recursive Equations
Build a solution by approximation (interpret functions as sets)

f0 = ∅

0 if x = 0
f1 =
f0 (x − 1) + 2x − 1 otherwise
= {(0, 0)}

0 if x = 0
f2 =
f1 (x − 1) + 2x − 1 otherwise
= {(0, 0), (1, 1)}

0 if x = 0
f3 =
f2 (x − 1) + 2x − 1 otherwise
= {(0, 0), (1, 1), (2, 4)}

305
Solving Recursive Equations

Model this process as higher-order function F that takes the


approximation fk as input and returns the next approximation.

F : (IN ⇀ IN) → (IN ⇀ IN)

where

0 if x = 0
(F (f ))(x) =
f (x − 1) + 2x − 1 otherwise

Iterate till a fixed point is reached (f = F (f ))

306
Fixed Point
Definition
Given a function F : A → A, a ∈ A is a fixed point of F if F (a) = a.
Notation: Write a = fix (F ) to indicate that a is a fixed point of F .

Idea: Compute fixed points iteratively, starting from the completely


undefined function. The fixed point is the limit of this process:

f =fix (F )
=f0 ∪ f1 ∪ f2 ∪ . . .
=∅ ∪ F (∅) ∪ F (F (∅)) ∪ . . .

[
= F i (∅)
i≥0

307
Denotational Semantics for while

C[[while b do c]] = fix (F )


where

F (f ) ={(s, s) | (s, false) ∈ B[[b]]} ∪


{(s, s′ ) | (s, true) ∈ B[[b]] ∧
∃s′′ . (s, s′′ ) ∈ C[[c]] ∧ (s′′ , s′ ) ∈ f }

308
Denotational Semantics – Example
C[[while !l ≥ 0 do m :=!l + !m ; l :=!l + (−1)]]

f0 = ∅

s if !l < 0
f1 =
undefined otherwise

s if !l < 0
f2 = s + {l 7→ −1, m 7→ s(m)} if !l = 0
undefined otherwise



 s if !l < 0
s + {l 7→ −1} if !l = 0

f3 =

 s + {l 7→ −1, m 7→ 1 + s(m)} if !l = 1
undefined otherwise

s if !l < 0


s + {l 7→ −1} if !l = 0


f4 = s + {l 7→ −1, m 7→ 1 + s(m)} if !l = 1
s + {l 7→ −1, m 7→ 3 + s(m)} if !l = 2



undefined otherwise
309
Fixed Points

• Why does (fix F ) have a solution?


• What if there are several solutions?
(which should we take)

310
Fixed Point Theory

Definition (sub preserving)


A function F preserves suprema if for every chain X1 ⊆ X2 ⊆ . . .
[ [
F ( Xi ) = F (Xi ) .
i i

Lemma
Every suprema-preserving function F is monotone increasing.

X ⊆ Y =⇒ F (X) ⊆ F (Y )

(works for arbitrary partially ordered sets)

311
Kleene’s fixed point theorem

Theorem
Let F be a suprema-preserving function. The least fixed point of F exists
and is equal to [
F i (∅)
i≥0

312
C[[while b do c]]

C[[while b do c]](s)
= fix (F )

C[[c]]k (s) if k ≥ 0 such that B[[b]](C[[c]]k (s)) = false
= and B[[b]](C[[c]]i (s)) = true for all 0 ≤ i < k
undefined if B[[b]](C[[c]]i (s)) = true for all i ≥ 0

This may be what you would have expected, but now it is grounded on
well-known mathematics

313
Exercises

• Show that skip ; c and c ; skip are equivalent.


• What does equivalent mean in the context of denotational
semantics?
• Show that (c1 ; c2 ) ; c3 is equivalent to c1 ; (c2 ; c3 ).

314
Section 16

Partial and Total Correctness

315
Styles of semantics

Operational
Meanings for program phrases defined in terms of the steps of
computation they can take during program execution.

Denotational
Meanings for program phrases defined abstractly as elements of some
suitable mathematical structure.

Axiomatic
Meanings for program phrases defined indirectly via the axioms and
rules of some logic of program properties.

316
Styles of semantics

Operational
– how to evaluate programs (interpreter)
– close connection to implementations

Denotational
Meanings for program phrases defined abstractly as elements of some
suitable mathematical structure.

Axiomatic
Meanings for program phrases defined indirectly via the axioms and
rules of some logic of program properties.

317
Styles of semantics

Operational
– how to evaluate programs (interpreter)
– close connection to implementations

Denotational
– what programs calculate (compiler)
– simplifies equational reasoning (semantic equivalence)

Axiomatic
Meanings for program phrases defined indirectly via the axioms and
rules of some logic of program properties.

318
Styles of semantics

Operational
– how to evaluate programs (interpreter)
– close connection to implementations

Denotational
– what programs calculate (compiler)
– simplifies equational reasoning (semantic equivalence)

Axiomatic
– describes properties of programs
– allows reasoning about the correctness of programs

319
Assertions
Axiomatic semantics describe properties of programs. Hence it requires
• a language for expressing properties
• proof rules to establish the validity of properties w.r.t. programs

Examples
• value of l is greater than 0
• value of l is even
• value of l is prime
• eventually the value of l will 0
• ...

320
Applications

• proving correctness
• documentation
• test generation
• symbolic execution
• bug finding
• malware detection
• ...

321
Assertion Languages

• (English)
• first-order logic (∀, ∃, ∧, ¬, =, R(x), . . . )
• temporal and modal logic (2, ⋄, ⊚, Until, . . . )
• special-purpose logics (Alloy, Z3, . . . )

322
Assertions as Comments
assertions are (should) be used in code regularly
/ * P r e c o n d i t i o n : 0 <= i < A . l e n g t h * /
/ * Postcodition : returns A[ i ] * /
p u b l i c i n t get ( i n t i ) {
return A[ i ] ;
}

• useful as documentation or run-time checks


• no guarantee that they are correct
• sometimes not useful (e.g. /*increment i*/)

aim: make this rigorous by defining the semantics of a language using


pre- and post-conditions

323
Partial Correctness

{P } c {Q}
Meaning: if P holds before c, and c executes and terminates then Q
holds afterwards

324
Partial Correctness – Examples

• {l = 21} l := !l + !l {l = 42}
• {l = 0 ∧ m = i}
k := 0 ;
while !l ̸= !m
do
k := !k − 2 ;
l := !l + 1
{k = −i − i}

Note: i is a ghost variable


we do not use dereferencing in conditions

325
Partial Correctness – Examples

The second example is a valid partial correctness statement.


Lemma

∀s, s . k, l, m ∈ dom(s) ∧ s(l) = 0 ∧
C[[k := 0 ; while !l ̸= !m do (k := !k − 2 ; l := !l + 1)]](s) = s′
=⇒ s′ (k) = −s(m) − s(m)

326
Partial Correctness – Examples

Is the following partial correctness statement valid?


• {l = 0 ∧ m = i}
k := 0 ;
while !l ̸= !m
do
k := !k + !l ;
l := !l + 1
{k = i}

327
Total Correctness

• partial correctness specifications do not ensure termination


• sometimes termination is needed

[P ] c [Q]
Meaning: if P holds, then c will terminate and Q holds afterwards

328
Total Correctness – Example

• [l = 0 ∧ m = i∧ i ≥ 0]
k := 0 ;
while !l ̸= !m
do
k := !k − 2 ;
l := !l + 1
[k = −i − i]

329
Assertions

What properties do we want to state in pre-conditions and


post-conditions; so far
• locations (program variables)
• equality
• logical/ghost variables (e.g. i)
• comparison
• we have not used ‘pointers’
choice of assertion language influences the sort of properties
we can specify

330
Assertions – Syntax
Booleans b∈B
Integers (Values) n∈Z
Locations l∈L = {l, l0 , l1 , l2 , . . . }
Logical variables i ∈ LVar = {i, i0 , i1 , i2 , . . . }
Operations aop ::= +
Expressions
aexpi ::= n | l | i | aexpi aop aexpi
assn ::= b | aexpi ≥ aexpi |
assn ∧ assn | assn ∨ assn |
assn ⇒ assn | ¬assn |
∀i. assn | ∃i. assn

Note: bexp included in assn; assn not minimal

331
Assertions – Satisfaction
when does a store s satisfy an assertion
• need interpretation for logical variables

I : LVar → Z

• denotation function AI [[ ]] (similar to A[[ ]]

AI [[n]](s, I) = n
AI [[l]](s, I) = s(l), l ∈ dom(s)
AI [[i]](s, I) = I(i), i ∈ dom(I)
AI [[a1 + a2 ]](s, I) = AI [[a1 ]](s, I) + A[[a2 ]](s, I)

332
Assertion Satisfaction
define satisfaction relation for assertions on a given state s
s |=I true
s |=I a1 ≥ a2 if AI [[a1 ]](s, I) ≥ AI [[a2 ]](s, I)
s |=I P1 ∧ P2 if s |=I P1 and s |=I P2
s |=I P1 ∨ P2 if s |=I P1 or s |=I P2
s |=I P1 ⇒ P2 if s ̸|=I P1 or s |=I P2
s |=I ¬P if s ̸|=I P
s |=I ∀i. P if ∀n ∈ Z. s |=I+{i7→n} P
s |=I ∃i. P if ∃n ∈ Z. s |=I+{i7→n} P

an assertion is valid (|= P ) if it is valid in any store, under any


interpretation
∀s, I. s |=I P

333
Partial Correctness – Satisfiability

A partial correctness statement {P } c {Q} is satisfied in store s and


under interpretation I (s |=I {P } c {Q}) if

∀s′ . if s |=I P and C[[c]](s) = s′ then s′ |=I Q .

334
Partial Correctness – Validity

Assertion validity
An assertion P is valid (holds) (|= P ) if it is valid in any store under
interpretation.
|= P :⇐⇒ ∀s, I. s |=I P

Partial correctness validity


A partial correctness statement {P } c {Q} is valid (|= {P } c {Q}) if it is
valid in any store under interpretation.

|= {P } c {Q} :⇐⇒ ∀s, I. s |=I {P } c {Q}

335
Proving Specifications

how to proof the (partial) correctness of {P } c {Q}


• show ∀s, I.s |=I {P } c {Q}
• s |=I {P } c {Q} requires denotational semantics C

• we can do this manually, but . . .


• we can derive inference rules and axioms (axiomatic semantics)
• allows derivation of correctness statements without reasoning about
stores and interpretations

336
Section 17

Axiomatic Semantics

337
Floyd-Hoare Logic

Idea: develop proof system as an inductively-defined set; every member


will be a valid partial correctness statement

Judgement
⊢ {P } c {Q}

338
Floyd-Hoare Logic – Skip

(skip) ⊢ {P } skip {P }

339
Floyd-Hoare Logic – Assignment

(assign) ⊢ {P [a/l]} l := a {P }

Notation: P [a/l] denotes substitution of a for l in P ;


in operational semantics we wrote {a/l} P

Example
{7 = 7} l := 7 {l = 7}

340
Floyd-Hoare Logic – Incorrect Assignment

(wrong1) ⊢ {P } l := a {P [a/l]}

Example
{l = 0} l := 7 {7 = 0}

(wrong2) ⊢ {P } l := a {P [l/a]}

Example
{l = 0} l := 7 {l = 0}

341
Floyd-Hoare Logic – Sequence, If, While

⊢ {P } c1 {R} ⊢ {R} c2 {Q}


(seq)
⊢ {P } c1 ; c2 {Q}

⊢ {P ∧ b} c1 {Q} ⊢ {P ∧ ¬b} c2 {Q}


(if)
⊢ {P } if b then c1 else c2 {Q}

⊢ {P ∧ b} c {P }
(while)
⊢ {P } while b do c {P ∧ ¬b}

P acts as loop invariant

342
Floyd-Hoare Logic – Consequence

We cannot combine arbitrary triple yet


...
(assign)
⊢ {3 = 3} l := 3 {l = 3} ⊢ {l ≥ 2} l :=!l − 2 {l ≥ 0}
⊢ {3 = 3} l := 3 ; l :=!l − 2 {l ≥ 0}

343
Floyd-Hoare Logic – Consequence

strengthen pre-conditions and weaken post-conditions

|= P ⇒ P ′ ⊢ {P ′ } c {Q′ } |= Q′ ⇒ Q
(cons)
⊢ {P } c {Q}

Recall: |= P ⇒ P ′ denotes assertion validity

344
Floyd-Hoare Logic – Summary
(skip) ⊢ {P } skip {P }

(assign) ⊢ {P [a/l]} l := a {P }

⊢ {P } c1 {R} ⊢ {R} c2 {Q}


(seq)
⊢ {P } c1 ; c2 {Q}
⊢ {P ∧ b} c1 {Q} ⊢ {P ∧ ¬b} c2 {Q}
(if)
⊢ {P } if b then c1 else c2 {Q}
⊢ {P ∧ b} c {P }
(while)
⊢ {P } while b do c {P ∧ ¬b}
|= P ⇒ P ′ ⊢ {P ′ } c {Q′ } |= Q′ ⇒ Q
(cons)
⊢ {P } c {Q}

345
Floyd-Hoare Logic – Exercise

{l0 = n ∧ n > 0}
l1 := 1 ;
while !l0 > 0 do
l1 := !l1 · !l0 ;
l0 := !l0 − 1
{l1 = n!}

346
Soundness and Completeness

how do ⊢ (judgement) and |= (validity) relate?

Soundness:
if a partial correctness statement can be derived (⊢) then is is valid (|=)

Completeness:
if the statement is valid (|=) then a derivation exists (⊢)

347
Soundness and Completeness

Theorem (Soundness)
If ⊢ {P } c {Q} then |= {P } c {Q}.

Proof.
Induction on the derivation of ⊢ {P } c {Q}. ⊔

348
Soundness and Completeness

Conjecture (Completeness)
If |= {P } c {Q} then ⊢ {P } c {Q}.

Rule (cons) spoils completeness


|= P ⇒ P ′ ⊢ {P ′ } c {Q′ } |= Q′ ⇒ Q
(cons)
⊢ {P } c {Q}

Can we derive |= P ⇒ P ′ ?
No, according to Gödel’s incompleteness theorem (1931)

349
Soundness and Completeness

Theorem (Relative Completeness)


P, Q ∈ assn, c ∈ com. |= {P } c {Q} implies ⊢ {P } c {Q}.

Floyd-Hoare logic is no more incomplete than our language of assertions

Proof depends on the notion of weakest liberal preconditions.

350
Decorated Programs

Observation: once loop invariants and uses of consequence are


identified, the structure of a derivation in Floyd-Hoare logic is determined
Write “proofs” by decorating programs with:
• a precondition ({P })
• a postcondition ({Q})
• invariants ({I}while b do c)
• uses of consequence ({R} ⇒ {S})
• assertions between sequences (c1 ; {T }c2 )
decorated programs describe a valid Hoare logic proof if the rest of the
proof tree’s structure is implied
(caveats: Invariants are constrained, etc.)

351
(Informal) Rules for Decoration

Idea: check whether a decorated program represents a valid proof using


local consistency checks

skip
pre and post-condition should be the same

{P } (skip) ⊢ {P } skip {P }
skip
{P }

352
(Informal) Rules for Decoration
assignment
use the substitution from the rule

{P [a/l]} (assign) ⊢ {P [a/l]} l := a {P }


l := a
{P }

sequencing
{P } c1 {R} and {R} c2 {Q} should be (recursively) locally consistent
⊢ {P } c1 {R} ⊢ {R} c2 {Q}
{P } (seq)
⊢ {P } c1 ; c2 {Q}
c1 ;
{R}
c2
{Q}

353
(Informal) Rules for Decoration
if then
both branches are locally consistent; add condition to both
⊢ {P ∧ b} c1 {Q} ⊢ {P ∧ ¬b} c2 {Q}
{P } (if)
⊢ {P } if b then c1 else c2 {Q}
if b then
{P ∧ b}
c1
{Q}
else
{P ∧ ¬b}
c2
{Q}
{Q}

354
(Informal) Rules for Decoration

while
add/create loop invariant
⊢ {P ∧ b} c {P }
{P } (while)
⊢ {P } while b do c {P ∧ ¬b}
while b do
{P ∧ b}
c
{P }
{P ∧ ¬b}

355
(Informal) Rules for Decoration

consequence
always write a (valid) implication
|= P ⇒ P ′ ⊢ {P ′ } c {Q′ } |= Q′ ⇒ Q
{P } ⇒ (cons)
⊢ {P } c {Q}
{P ′ }

356
Floyd-Hoare Logic – Exercise

{l0 = n ∧ n > 0}
l1 := 1 ;
while !l0 > 0 do
l1 := !l1 · l0 ;
l0 := !l0 − 1
{l1 = n!}

357
Floyd-Hoare Logic – Exercise
{l0 = n ∧ n > 0} ⇒
{1 = 1 ∧ l0 = n ∧ n > 0}
l1 := 1 ;
{l1 = 1 ∧ l0 = n ∧ n > 0} ⇒
{l1 · l0 ! = n! ∧ l0 ≥ 0}
while !l0 > 0 do
{l1 · l0 ! = n! ∧ l0 > 0 ∧ l0 ≥ 0} ⇒
{l1 · l0 · (l0 − 1)! = n! ∧ (l0 − 1) ≥ 0}
l1 := !l1 · l0 ;
{l1 · (l0 − 1)! = n! ∧ (l0 − 1) ≥ 0}
l0 := !l0 − 1
{l1 · l0 ! = n! ∧ l0 ≥ 0}
{l1 · l0 ! = n! ∧ (l0 ≥ 0) ∧ ¬(l0 > 0)} ⇒
{l1 = n!}
358
Section 18

Weakest Preconditions

359
Generating Preconditions

{ ? } c {Q}

• many possible preconditions


• some are more useful than others

360
Weakest Liberal Preconditions

Intuition: the weakest liberal precondition for c and Q is the weakest


assertion P such that {P } c {Q} is valid

Definition (Weakest Liberal Precondition)


P is a weakest liberal precondition of c and Q (wlp(c, Q)) if

∀s, I. s |=I P ⇐⇒ C[[c]](s) is undefined ∨ C[[c]](s) |=I Q

361
Weakest Preconditions
wlp(skip, Q) = Q
wlp(l := a, Q) = Q[a/l]
wlp((c1 ; c2 ), Q) = wlp(c1 , wlp(c2 , Q))
wlp(if b then c1 else c2 , Q) = (b =⇒ wlp(c1 , Q)) ∧
(¬b =⇒ wlp(c2 , Q))
wlp(while b do c, Q) = (b =⇒ wlp(c, wlp(while b do c, Q))) ∧
(¬b =⇒ Q)
^
= Fi (Q)
i

where
F0 (Q) = true
Fi+1 (Q) = (¬b =⇒ Q) ∧ (b =⇒ wlp(c, Fi (Q)))
(Greatest fixed point)
362
Properties of Weakest Preconditions

Lemma (Correctness of wlp)


∀c ∈ com, Q ∈ assn.
|= {wlp(c, Q)} c {Q} and
∀R ∈ assn. |= {R} c {Q} implies (R =⇒ wlp(c, Q))

Lemma (Provability of wlp)


∀c ∈ com, Q ∈ assn. ⊢ {wlp(c, Q)} c {Q}

363
Soundness and Completeness

Theorem (Relative Completeness)


P, Q ∈ assn, c ∈ com. |= {P } c {Q} implies ⊢ {P } c {Q}.
Proof Sketch.
• let {P } c {Q} be a valid partial correctness specification
• by the first lemma we have |= P =⇒ wlp(c, Q)
• by the second lemma we have ⊢ {wlp(c, Q)} c {Q}
• hence ⊢ {P } c {Q}, using the Rule (cons)

364
Total Correctness
Definition (Weakest Precondition)
P is a weakest precondition of c and Q (wp(c, Q)) if

∀s, I. s |=I P ⇐⇒ C[[c]](s) |=I Q

all rules are the same, except the one for while. This requires a fresh
ghost variable that guarantees termination

Lemma (Correctness of wp)


∀c ∈ com, Q ∈ assn.
|= [wp(c, Q)] c [Q] and
∀R ∈ assn. |= [R] c [Q] implies (R =⇒ wp(c, Q))
(for appropriate definition of |=)

365
Strongest Postcondition

{P } c { ? }
• wlp motivates backwards reasoning
• this seems unintuitive and unnatural
• however, often it is known what a program is supposed to do
• sometimes forward reasoning is useful, e.g. reverse engineering

366
Strongest Postcondition

sp(skip, P ) = P
sp(l := a, P ) = ∃v. (l = a[v/l] ∧ P [v/l])
sp((c1 ; c2 ), P ) = sp(c2 , sp(c1 , P ))
sp(if b then c1 else c2 , P ) = (sp(c1 , b ∧ P )) ∨ (sp(c2 , ¬b ∧ P ))
sp(while b do c, P ) = sp(while b do c, sp(c, P ∧ b)) ∨ (¬b ∧ P )

where
F0 (P ) = false
Fi+1 (P ) = (¬b ∧ P ) ∨ (sp(c, Fi (P ∧ b)))

(Least fixed point)

367
Section 19

Concurrency

368
Concurrency and Distribution

so far we concentrated on semantics for sequential computation


but the world is not sequential. . .
• hardware is intrinsically parallel
• multi-processor architectures
• multi-threading (perhaps on a single processor)
• networked machines

369
Problems
aim: languages that can be used to model computations that execute in
parallel and on distributed architectures
problems
• state-space explosion
with n threads, each of which can be in 2 states, the system has 2n states
• state-spaces become complex
• computation becomes nondeterministic
• competing for access to resources may deadlock or suffer starvation
• partial failure (of some processes, of some machines in a network, of some
persistent storage devices)
• communication between different environments
• partial version change
• communication between administrative regions with partial trust (or, indeed,
no trust)
• protection against malicious attack
• ...
370
Problems

this course can only scratch the surface

concurrency theory is a broad and active field for research

371
Process Calculi

• Observation (1970s): computers with shared-nothing architectures


communicating by sending messages to each other would be
important
[Edsger W. Dijkstra, Tony Hoare, Robin Milner, and others]
• Hoare’s Communicating Sequential Processes (CSP) is an early
and highly-influential language that capture a message passing form
of concurrency
• many languages have built on CSP including Milner’s CCS and
π-calculus, Petri nets, and others

372
IMP – Parallel Commands
we extend our while-language that is based on aexp, bexp and com

Syntax
com ::= . . . | com ∥ com

Semantics
⟨c0 , s⟩ −→ ⟨c′0 , s′ ⟩
(par1)
⟨c0 ∥ c1 , s⟩ −→ ⟨c′0 ∥ c1 , s′ ⟩

⟨c1 , s⟩ −→ ⟨c′1 , s′ ⟩
(par2 )
⟨c0 ∥ c1 , s⟩ −→ ⟨c0 ∥ c′1 , s′ ⟩

373
IMP – Parallel Commands

Typing

Γ ⊢ c : unit
(thread)
Γ ⊢ c : proc

Γ ⊢ c0 : proc Γ ⊢ c1 : proc
(par )
Γ ⊢ c0 ∥ c1 : proc

374
Parallel Composition: Design Choices

• threads do not return a value


• threads do not have an identity
• termination of a thread cannot be observed within the language
• threads are not partitioned into ‘processes’ or machines
• threads cannot be killed externally

375
Asynchronous Execution
• semantics allow interleavings
⟨skip ∥ l := 2 , {l 7→ 1}⟩ / ⟨skip ∥ skip , {l 7→ 2}⟩
2
⟨l := 1 ∥ l := 2 , {l 7→ 0}⟩
,
⟨l := 1 ∥ skip , {l 7→ 2}⟩ / ⟨skip ∥ skip , {l 7→ 1}⟩

• assignments and dereferencing are atomic


⟨skip ∥ l := 2 , {l 7→ N }⟩ / ⟨skip ∥ skip , {l 7→ 2}⟩
2
⟨l := N ∥ l := 2 , {l 7→ 0}⟩
,
⟨l := N ∥ skip , {l 7→ 2}⟩ / ⟨skip ∥ skip , {l 7→ N }⟩
for N = 3498734590879238429384.
(not something as the first word of one and the second word of the other)

376
Asynchronous Execution
• interleavings in ⟨(l := 1+!l) ∥ (l := 7+!l) , {l 7→ 0}⟩

⟨(skip ∥ (l := 7+!l) , {l 7→ 1}⟩


r /• +
/• w / ⟨(skip ∥ (skip , {l 7→ 8}⟩
6
w

⟨(l := 1) ∥ (l := 7+!l) , {l 7→ 0}⟩ ⟨skip ∥ (l := 7 + 0) , {l 7→ 1}⟩


5 6
+ r w +

( &
⟨(l := 1 + 0) ∥ (l := 7+!l) , {l 7→ 0}⟩ ⟨(l := 1) ∥ (l := 7 + 0) , {l 7→ 0}⟩ ⟨skip ∥ (l := 7) , {l 7→ 1}⟩
w / ⟨skip ∥ skip , {l 7→ 7}⟩
5 6 8
r r + + w

) (
⟨(l := 1+!l) ∥ (l := 7+!l) , {l 7→ 0}⟩ ⟨(l := 1 + 0 ∥ (l := 7 + 0) , {l 7→ 0}⟩ ⟨(l := 1) ∥ (l := 7) , {l 7→ 0}⟩
5 6
r r + + w

) ( &
⟨(l := 1+!l) ∥ (l := 7 + 0) , {l 7→ 0}⟩ ⟨(l := 1 + 0) ∥ (l := 7) , {l 7→ 0}⟩ ⟨(l := 1) ∥ skip , {l 7→ 7}⟩
w / ⟨skip ∥ skip , {l 7→ 1}⟩
6 8
+ r w +

) (
⟨(l := 1+!l) ∥ (l := 7) , {l 7→ 0}⟩ ⟨(l := 1 + 0) ∥ skip , {l 7→ 7}⟩
w

(
⟨(l := 1+!l) ∥ skip , {l 7→ 0}⟩
r /• +
/• w / ⟨(skip ∥ (skip , {l 7→ 8}⟩

377
Morals

• combinatorial explosion
• drawing state-space diagrams only works for really tiny examples
• almost certainly the programmer does not want all those 3
outcomes to be possible
• complicated/impossible to analyse without formal methods

378
Parallel Commands – Nondeterminism
Semantics
⟨c0 , s⟩ −→ ⟨c′0 , s′ ⟩
(par1)
⟨c0 ∥ c1 , s⟩ −→ ⟨c′0 ∥ c1 , s′ ⟩
⟨c1 , s⟩ −→ ⟨c′1 , s′ ⟩
(par2 )
⟨c0 ∥ c1 , s⟩ −→ ⟨c0 ∥ c′1 , s′ ⟩
(+maybe rules for termination)

• study of nondeterminism
• ∥ is not a partial function from state to state; big-step semantics
needs adaptation
• can we achieve parallelism by nondeterministic interleavings
• communication via shared variable

379
Study of Parallelism (or Concurrency)
includes
Study of Nondeterminism

380
Dijkstra’s Guarded Command Language (GCL)

• defined by Edsger Dijkstra for predicate transformer semantics


• combines programming concepts in a compact/abstract way
• simplicity allows correctness proofs
• closely related to Hoare logic

381
GCL – Syntax
• arithmetic expressions: aexp (as before)
• Boolean expressions: bexp (as before)
• Commands:

com ::= skip | abort | l := aexp | com ; com |


if gc fi | do gc od

• Guarded Commands:

gc ::= bexp → com |


gc [] gc

382
GCL – Semantics
• assume we have semantic rules for bexp and aexp (standard)
we skip the deref-operator from now on
• assume a new configuration fail

Guarded Commands
⟨b , s⟩ −→ ⟨true , s⟩ ⟨b , s⟩ −→ ⟨false , s⟩
(pos) (neg)
⟨b → c , s⟩ −→ ⟨c , s⟩ ⟨b → c , s⟩ −→ fail

⟨gc0 , s⟩ −→ ⟨c , s′ ⟩ ⟨gc1 , s⟩ −→ ⟨c , s′ ⟩
(par1) (par2)
⟨gc0 [] gc1 , s⟩ −→ ⟨c , s′ ⟩ ⟨gc0 [] gc1 , s⟩ −→ ⟨c , s′ ⟩

⟨gc0 , s⟩ −→ fail ⟨gc1 , s⟩ −→ fail


(par3)
⟨gc0 [] gc1 , s⟩ −→ fail

383
GCL – Semantics
Commands

• skip and sequencing ; as before (can drop determinacy)


• abort has no rules

⟨gc , s⟩ −→ ⟨c , s′ ⟩
(cond)
⟨if gc fi , s⟩ −→ ⟨c , s′ ⟩

⟨gc , s⟩ −→ fail
(loop1) †
⟨do gc od , s⟩ −→ ⟨⟨s⟩⟩

⟨gc , s⟩ −→ ⟨c , s′ ⟩
(loop2)
⟨do gc od , s⟩ −→ ⟨c ; do gc od , s′ ⟩

new notation: behaves like skip

384
Processes

do b1 → c1 [] · · · [] bn → cn od

• form of (nondeterministically interleaved) parallel composition


• each ci occurs atomically (uninterruptedly),
provided bi holds each time it starts

Some languages support/are based on GCL


• UNITY (Misra and Chandy)
• Hardware languages (Staunstrup)

385
GCL – Examples
• compute the maximum of x and y
if
x ≥ y → max := x
[]
y ≥ x → max := y
fi

• Euclid’s algorithm
do
x > y → x := x − y
[]
y > x → y := y − x
od

386
GCL and Floyd-Hoare logic

guarded commands support a neat Hoare logic and decorated programs

Hoare triple for Euclid

{x = m ∧ y = n ∧ m > 0 ∧ n > 0}
Euclid
{x = y = gcd(m, n)}

387
Proving Euclid’s Algorithm Correct

• recall gcd(m, n)|m, gcd(m, n)|n and

ℓ|m, n ⇒ ℓ| gcd(m, n)

• invariant: gcd(m, n) = gcd(x, y)


• key properties:

gcd(m, n) = gcd(m − n, n) if m > n


gcd(m, n) = gcd(m, n − m) if n > m
gcd(m, m) = m

388
Synchronised Communication

• communication by “handshake”
• possible exchange of value
(localised to process-process (CSP) or to a channel (CCS))
• abstracts from the protocol underlying coordination
• invented by Hoare (CSP) and Milner (CCS)

389
Extending GCL

• allow processes to send and receive values on channels


α!a evaluate expression a and send value on channel α
α?x receive value on channel α and store it in x
• all interactions between parallel processes is by sending / receiving
values on channels
• communication is synchronised (no broadcast yet)
• allow send and receive in commands c and in guards g:

do y < 100 ∧ α?x → α!(x · x) ∥ y := y + 1 od

390
Extending GCL – Semantics
transitions may carry labels when possibility of interaction
⟨a , s⟩ −→ ⟨n , s⟩
α?n α!n
⟨α?x , s⟩ −→ ⟨⟨s + {x 7→ n}⟩⟩ ⟨α!a , s⟩ −→ ⟨⟨s⟩⟩
λ
⟨c0 , s⟩ −→ ⟨c′0 , s′ ⟩
λ
(+ symmetric)
⟨c0 ∥ c1 , s⟩ −→ ⟨c′0 ∥ c1 , s′ ⟩

α?n α!n
⟨c0 , s⟩ −→ ⟨c′0 , s′ ⟩ ⟨c1 , s⟩ −→ ⟨c′1 , s⟩
(+ symmetric)
⟨c0 ∥ c1 , s⟩ −→ ⟨c′0 ∥ c′1 , s′ ⟩
λ
⟨c , s⟩ −→ ⟨c′ , s′ ⟩
λ
λ ̸∈ {α?n, α!n}
⟨c\α , s⟩ −→ ⟨c′ \α , s′ ⟩

λ may be the empty label


391
Examples

• forwarder:
do α?x → β!x od

• buffer of capacity 2:

do α?x → β!x od

∥ do β?x → γ!x od \β

392
External vs Internal Choice
the following two processes are not equivalent w.r.t. deadlock capabilities

if (true ∧ α?x → c0 ) [] (true ∧ β?x → c1 ) fi

if (true → α?x ; c0 ) [] (true → β?x ; c1 ) fi

393
Section 20

The Process Algebra CCS

394
Towards an Abstract Mechanism for Concurrency

The Calculus of Communicating Systems (CCS)


• introduced by Robin Milner in 1980
• first process calculus developed with its operational semantics
• supports algebraic reasoning about equivalence
• simplifies Dijkstra’s GCL by removing the store

395
Actions and Communications

• processes communicate values (numbers) on channels


• communication is synchronous and between two processes
• a is an arithmetic expression; evaluation is written a → n
• input: α?x
• output α!a
• silent actions τ (internal to a process)
• λ will range over all the kinds of actions, including τ

396
(Decorated) CCS – Syntax
Expressions:
arithmetic a and Boolean b

Processes:
p ::= nil nil process
| (τ → p) silent/internal action
| (α!a → p) output
| (α?x → p) input
| (b → p) Boolean guard
| p+p nondeterministic choice
| p∥p parallel composition
| p\L restriction (L a set of channel identifiers)
| p[f ] relabelling (f a function on channel identifiers)
| P (a1 , . . . , ak ) process identifier

397
(Decorated) CCS – Syntax

Process Definitions:
def
P (x1 , . . . , xk ) = p

(free variables of p ⊆ {x1 , . . . , xk })

398
Restriction and Relabelling – Examples

• p\L: disallow external interaction on channels in L


• p[f ]: rename external interface to channels by f

399
Operational semantics of CCS
Guarded processes

silent action
τ
(τ → p) −→ p

output
a −→ n
α!n
(α!a → p) −→ p

input
α?n
(α?x → p) −→ p[n/x]

Boolean
λ
b → true p −→ p′
λ
(b → p) −→ p′

400
Operational semantics of CCS
Sum
λ λ
p0 −→ p′0 p1 −→ p′1
λ λ
p0 + p1 −→ p′0 p0 + p1 −→ p′1

Parallel composition
λ α?n α!n
p0 −→ p′0 p0 −→ p′0 p1 −→ p′1
τ
λ
p0 ∥ p1 −→ p′0 ∥ p1 p0 ∥ p1 −→ p′0 ∥ p′1

λ α!n α?n
p1 −→ p′1 p0 −→ p′0 p1 −→ p′1
τ
λ
p0 ∥ p1 −→ p0 ∥ p′1 p0 ∥ p1 −→ p′0 ∥ p′1

401
Operational semantics of CCS
Restriction λ
p −→ p′
λ
if λ ∈ {α?n, α!n} then α ̸∈ L
p\L −→ p′ \L

λ
Relabelling p −→ p′
f (λ)
p[f ] −→ p′ [f ]
where f is extended to labels as f (τ ) = τ and f (α?n) = f (α)?n and
f (α!n) = f (α)!n

Identifiers λ
p[a1 /x1 , . . . , an /xn ] −→ p′ def
λ
P (x1 , . . . , xn ) = p
P (a1 , . . . , an ) −→ p′

Nil process
no rules
402
A Derivation

τ
(((α!3 → nil + P ) ∥ τ → nil) ∥ α?x → nil)\{α} −→ ((nil ∥ τ → nil) ∥ nil)\{α}

403
More Examples

• Mixed choice α!2 → nil + τ → β!3 → nil


α!2 τ

v )
nil β!3 → nil

β!3

nil

404
Linking Process
(some syntactic sugar)

Let
def
P =in?x → out!x → P
def
Q =in?y → out!y → Q

Connect P ’s output port to Q’s input port


P Q = (P [c/out] ∥ Q[c/in])\{c}

where c is a fresh channel name

405
Euclid’s algorithm in CSS

def
E(x, y) = x = y → gcd!x → nil
+ x < y → E(x, y − x)
+ y < x → E(x − y, x)

def
Euclid = in?x → in?y → E(x, y)

406
Section 21

Pure CCS

407
Towards a more basic language
aim: removal of variables to reveal symmetry of input and output
• transitions for value-passing carry labels τ , a?n, a!n

α?x → p
α?0 / p[0/x]

α?n
%
p[n/x]

• this suggests introducing prefix α?n.p


P (as well as α!n.p) and
view α?x → p as a (infinite) sum n α?n.p[n/x]
• view α?n and α!n as complementary actions
• synchronisation can only occur on complementary actions

408
Pure CCS
• Actions: a, b, c, . . .
• Complementary actions: ā, b̄, c̄,. . .
• Internal action: τ
• ¯=a
Notational convention: ā
• Processes:
p ::= P
λ.p prefix λ ranges over τ, a, ā for any action
| i∈I pi sum I is an index set
| p0 ∥ p1 parallel
| p\L restriction L a set of actions
| p[f ] relabelling f a relabelling function on actions
| P process identifier

• Process definitions:
def
P =p

409
Pure CCS – Semantics
Guarded processes (prefixing)
λ
λ.p −→ p

Sum
λ
pj −→ p′
λ
j∈I

P
i∈I pi −→ p

Parallel composition
λ λ
p0 −→ p′0 p1 −→ p′1
λ λ
p0 ∥ p1 −→ p′0 ∥ p1 p0 ∥ p1 −→ p0 ∥ p′1
a ā
p0 −→ p′0 p1 −→ p′1
τ
p0 ∥ p1 −→ p′0 ∥ p′1

410
Pure CCS – Semantics
Restriction
λ
p −→ p′
λ
λ ̸∈ L ∪ L
p\L −→ p′ \L
where L = {ā | a ∈ L}

Relabelling
λ
p −→ p′
λ
p[f ] −→ p′ [f ]
where f is a function such that f (τ ) = τ and f (ā) = f (a)

Identifiers
λ
p −→ p′ def
λ
P =p
P −→ p′

411
From Value-passing to Pure CCS
translation from a value-passing CCS closed term p to a pure CCS term pb

p pb
nil nil
(τ → p) τ.b
p
(α!a → p) αm.bp where a evaluates to m
P \
(α?x → p) m∈int αm.p[m/x]
(b → p) pb if b evaluates to true
nil if b evaluates to false
p0 + p1 pb0 + pb1
p0 ∥ p1 pb0 ∥ pb1
p\L pb\{αm | α ∈ L ∧ m ∈ int}
P (a1 , . . . , ak ) Pm1 ,...,mk where ai evaluates to mi
For every definition P (x1 , . . . , xk ) we have a collection of definitions
Pm1 ,...,mk indexed by m1 ,. . . ,mk ∈ int
412
Correspondence

Theorem
λ λ
p −→ p′ iff pb −→ pb′
b

413
Section 22

Semantic Equivalences

414
Labelled Transition Systems

CCS naturally implies a graphical model of computation.

a labelled transition system (LTS) is a pair (S, ⇒) with


• S a set (of states or processes), and
• ⇒ ⊆ S × Act × S, the transition relation.
here Act = A ⊎ {τ } is a set of actions, containing visible actions
a, b, c, ... ∈ A, and the invisible action τ .
λ 1 λ 2 λ n
a finite path is a sequence p0 −→ p1 −→ · · · −→ pn with pi ∈ S for
i = 0, ..., n and (pi−1 , λi , pi ) ∈ ⇒ for all i = 1, ..., n.

415
Trace equivalence

• if such a path exists, then the sequence λ1 λ2 . . . λn is a (partial)


trace of the process p0
• two processes p and q are (partial) trace equivalent if they have the
same (partial) traces.

416
Four Kinds of Trace Equivalence

Let T ∗ (p) be the set of (partial) traces of process p ∈ S.


Let T ∞ (p) be the set of infinite traces of p.
Let CT ∗ (p) be the set of completed traces of p.
Let CT ∞ (p) := CT ∗ (p) ⊎ T ∞ (p).

A finite trace is complete if it last state has no outgoing transition.

Write p =∗T q if T ∗ (p) = T ∗ (q) — (partial) trace equivalence.


Write p =∗CT q if CT ∗ (p) = CT ∗ (q) and T ∗ (p) = T ∗ (q) —
completed trace equivalence
Write p =∞T q if T ∞
(p) = T ∞
(q) and T ∗
(p) = T ∗ (q) —
infinitary trace equivalence
Write p =∞CT if CT ∞
(p) = CT ∞
(q) — infinitary completed tr. eq.

417
A Lattice of Semantic Equivalence Relations
A relation ∼ ⊆ S × S on processes is an equivalence relation if it is
• reflexive: p ∼ p,
• symmetric: if p ∼ q then q ∼ p,
• and transitive: if p ∼ q and q ∼ r then p ∼ r.
Let [p]∼ be the equivalence class of p: the set of all processes that are
∼-equivalent to p.
[p]∼ := {q ∈ S | q ∼ p}.

Equivalence relation ∼ is finer than equivalence relation ≈ iff

p ∼ q ⇒ p ≈ q.

Thus if ∼ ⊆ ≈. In that case each equivalence class of ∼ is included in an


equivalence class of ≈.
418
Four Additional Trace Equivalence

A weak trace is obtained from a strong one by deleting all τ s.


Let W T ∗ (p) := {detau(σ) | σ ∈ T ∗ (p)}.

This leads to weak trace equivalences =∗W T , =∞ ∗ ∞


W T , =W CT , =W CT .

419
Safety and Liveness Properties
A safety property says that something bad will never happen.
A liveness property says that something good will happen eventually.

If we deem two processes p and q semantically equivalent we often want


them to have the same safety and/or liveness properties.
?
ab ∼ ab + a

Weak partial trace equivalence respects safety properties.


?
ag ∼ ag + a

We need at least completed traces to deal with liveness properties

420
Compositionality
If p ∼ q then C[p] ∼ C[q].
Here C[ ] is a context, made from operators of some language.

For instance ( |b̄.ā.nil)\{a, b} is a CCS-context.


If p ∼ q then (p|b̄.ā.nil)\{a, b} ∼ (q|b̄.ā.nil)\{a, b}.

Then ∼ is a congruence for the language,


or the language if compositional for ∼.

p ∼ p′ ⇒ (p|p|...|p)\L ∼ (p′ |p′ |...|p′ )\L.

a.b + a.c =∗CT a.(b + c) but


̸ ∗CT (a.(b + c)|ā.b̄)\{a, b}.
((a.b + a.c)|ā.b̄)\{a, b} =

Thus =∗CT is a not a congruence for CCS.

421
Congruence closure

Theorem: Given any equivalence ≈ that need not be a congruence for


some language L, there exists a coarsest congruence ∼ for L that is
finer than ∼.

In fact, ∼ can be defined by

p∼q :⇔ C[p] ≈ C[q] for any L-context C[ ].

422
Bisimulation equivalence

A relation R ⊆ S × S is a bisimulation if it satisfies:


λ λ
• if pRq and p −→ p′ then ∃q ′ s.t. q −→ q ′ and p′ Rq ′ , and
λ λ
• if pRq and q −→ q ′ then ∃p′ s.t. p −→ p′ and p′ Rq ′ .
Two processes p, q ∈ S are bisimulation equivalent or bisimilar
—notation p =B q—if pRq for some bisimulation R.

Examples: a.b + a.c ̸=B a.(b + c) a.b + a.b =B a.b

423
Weak bisimulation equivalence

A relation R ⊆ S × S is a weak bisimulation if it satisfies:


λ (λ)
• if pRq and p −→ p′ then ∃q ′ s.t. q =⇒−→=⇒ q ′ and p′ Rq ′ ,
and
λ (λ)
• if pRq and q −→ q ′ then ∃p′ s.t. p =⇒−→=⇒ p′ and p′ Rq ′ .
Here =⇒ denotes a finite sequence of τ -steps,
and (λ) means λ, except that it is optional in case λ = τ .
(λ) λ
(That is, p −→ q iff p −→ q ∨ (λ = τ ∧ q = p).)
Two processes p, q ∈ S are weakly bisimilar
—notation p =W B q—if pRq for some bisimulation R.

Examples: τ.b + c ̸=W B b + c τ.b + b =W B b

424
Semantic Equivalences – Summary

• relate to systems (via LTSs)


• can be extended to states carrying stores
• sos-rules give raise to LTSs in a straightforward way
• reduce complicated (big) systems to simpler ones
• smaller systems may be easier to verify
• understand which properties are preserved

425
Section 23

The Owicki-Gries Method

426
Motivation

• nondeterminism and concurrency required


• handle interleaving
• Floyd-Hoare logic only for sequential programs

• Owicki-Gries Logic/Method
▶ a.k.a. interference freedom
▶ Susan Owicki and PhD supervisor David Gries
▶ add a construct to the programming language for threads
▶ study the impact for Hoare triples

427
Floyd-Hoare Logic and Decorated Programs

Notation: processes: individual program


system: overall (concurrent) program will be

Floyd-Hoare logic
• each of the individual processes has an assertion
▶ before its first statement (precondition)
▶ between every pair of its statements (pre-/postcondition), and
▶ after its last statement (postcondition)
• Hoare-triples can be checked (local correctness)
• Floyd-Hoare logic is compositional

428
Motivation
add pre- and postcondition for system, and a rule

{P1 } c1 {Q1 } {P2 } c2 {Q2 }


{P1 ∧ P2 } c1 ∥ c2 {Q1 ∧ Q2 }

but this rule is incorrect

Note: we are considering an interleaving semantics

429
Simple Example

{x == 0}

{x == 0 ∨ x == 2} {x == 0 ∨ x == 1}

x := x + 1 ∥ x := x + 2

{x == 1 ∨ x == 3} {x == 2 ∨ x == 3}

{x == 3}

What would we have to show?

430
The Rule of Owicki Gries

all rules of Floyd-Hoare logic remain valid

{P1 } c1 {Q1 } . . . {Pn } cn {Qn } interference freedom


(par)
{P1 ∧ · · · ∧ Pn } c1 ∥ · · · ∥ cn {Q1 ∧ · · · ∧ Qn }

431
Interference Freedom

Interference freedom is a property of proofs of the {Pi } ci {Qi }


• suppose we have a proof for {Pi } ci {Qi }
• prove that the execution of any other statement cj does not validate
the reasoning for {Pi } ci {Qi }

it is a bit tricky
• interference freedom is a property of proofs, not Hoare triples
• identifying which parts of a proof need to be considered requires
some effort

432
Formalising Interference Freedom

In a decorated program D and command c of the program, let


• pre(D, c) be the precondition (assumption/predicate) immediately
before c, and
• post(D, c) the postcondition immediately after c
• remember {P } c {Q} valid if there is a decorated program D with
pre(D, c) = P and post(D, c) = Q

433
Formalising Interference Freedom
{P1 } c1 {Q1 } . . . {Pn } cn {Qn } interference freedom
(par)
{P1 ∧ · · · ∧ Pn } c1 ∥ · · · ∥ cn {Q1 ∧ · · · ∧ Qn }

Suppose every ci has a decorated program Dci .


Definition
Dci is interference-free with respect to Dcj (i ̸= j) if for each statement c′i
in ci and c′j in cj
• {pre(Dci , c′i ) ∧ pre(Dcj , c′j )} c′j {pre(Dci , c′i )}
• {post(Dci , c′i ) ∧ pre(Dcj , c′j )} c′j {post(Dci , c′i ))}
The Dc1 , Dc1 , . . . Dcn are interference-free if they are pairwise
interference-free with respect to one other.

434
Interference Freedom – Remark

• applying the Rule (par) requires the development of


interference-free decorated programs for the ci
• proving interference-freedom of Dci with respect to Dcj focusses on
▶ preconditions of each statement in ci and postcondition of Dci

435
Simple Example

Why is interference freedom violated?


{x == 0}

{x == 0} {x == 0}

x := x + 1 ∥ x := x + 2

{x == 1} {x == 1}

{x == 1}

436
Soundness

Theorem
If {P } c {Q} is derivable using the proof rules seen so far then c is valid

437
Completeness

Can every correct Hoare triple be derived?

• completeness does not hold


• neither does relative completeness

438
Incompleteness
Lemma
The following valid Hoare triple cannot be derived using the rules so far.

{true} x := x + 2 ∥ x := 0 {x == 0 ∨ x == 2}

Proof.
By contradiction. Suppose there were such a proof. Then there would be Q, R such that
{true} x := x + 2 {Q}
{true} x := 0 {R}
Q ∧ R =⇒ x == 0 ∨ x == 2

By (assign) {P [a/l]} l := a {P } , true =⇒ Q[x + 2/x] holds. Similarly, R[0/x] holds.
By (par), {R ∧ true} x := x + 2 {R} holds, meaning R ⇒ R[x + 2/x] is valid.
But then by induction, ∀x. (x ≥ 0 ∧ even(x)) =⇒ R is true. Since
Q ∧ R =⇒ x = 0 ∨ x = 2, it follows that
∀x. (x ≥ 0 ∧ even(x)) =⇒ (x == 0 ∨ x == 2) ,
which is a contradiction. ⊓

439
Fixing the Problem

We showed
• R must hold for all even, positive x
• R must hold after execution of x := 0
• R must also hold both before and after execution of x := x + 2

we need the capability in R to say that


until x := x + 2 is executed, x = 0 holds.

440
Auxiliary Variables
variables that are put into a program just to reason about progress in
other processes

done := 0 ;
(
x, done := x + 2, 1

x := 0
)

• requires synchronous/atomic assignment


• proof is now possible

441
Decorated Programs with Auxiliary Variables
{true}
done := 0 ;
{done == 0}
(
{done == 0}
x, done := x + 2, 1
{true}

{true}
x := 0
{(x == 0 ∨ x == 2) ∧ (done == 0 ⇒ x == 0)}
)
{c == 0 ∨ x == 2}

Note: some implications skipped in the decorated program


442
Relative Completeness
• adding auxiliary variables enables proofs
• we do not want these variables to be in our code

{P } c {Q} x not free in Q x auxiliary in c


(aux)
{P } c′ {Q}
where c′ is c with all references to x removed.

Theorem (Relative Completeness)


Adding Rules (par) and (aux) to the other rules of Floyd-Hoare logic
yields a relatively complete proof system.

443
Problem

The Owicki-Griess Methods is not compositional.

444
Peterson’s Algorithm for Mutual exclusion
the following 4 lines of (symmetric) code took 15 years to discover
(mid 60’s to early 80s)

let a, b be Booleans and t : {A, B}

{¬a ∧ ¬b}
other code of A other code of B
a := true b := true
t := A t := B
await (¬b ∨ t == B) await (¬a ∨ t == A)
critical section A critical section B
a := false b := false

445
Notes on Peterson’s Algorithm

• protects critical sections from mutual destructive interference


• guarantees fair treatment of A and B

• how do we show that A (or B) is never perpetually ignored in favour


of B (A)?
▶ requires liveness in this case
▶ a topic for another course/research project
▶ in fact there is one line that could potentially violate liveness
(requires knowledge about hardware)

• 4 correct lines of code in 15 years is a coding rate of roughly


1 LoC every 4 years

446
Yet Another Example

FindFirstPositive

i := 0 ; j := 1 ; x := |A| ; y := |A| ;
while i < min(x, y) do while j < min(x, y) do
if A[i] > 0 then if A[j] > 0 then
x := i ∥ y := j
else else
i := i + 2 j := j + 2
r := min(x, y)

447
i := 0 ; j := 1 ; x := |A| ; y := |A| ;
{P1 ∧ P2 }
{P1 } {P2 }
while i < min(x, y) do while j < min(x, y) do
{P1 ∧ i < x ∧ i < |A|} {P2 ∧ j < y ∧ j < |A|}
if A[i] > 0 then if A[j] > 0 then
{P1 ∧ i < x ∧ i < |A| ∧ A[i] > 0} {P2 ∧ j < y ∧ j < |A| ∧ A[j] > 0}
x := i y := j
{P1 } ∥ {P2 }
else else
{P1 ∧ i < x ∧ i < |A| ∧ A[i] ≤ 0} {P2 ∧ j < y ∧ j < |A| ∧ A[j] ≤ 0}
i := i + 2 j := j + 2
{P1 } {P2 }
{P1 } {P2 }
{P1 ∧ i ≥ min(x, y)} {P2 ∧ j ≥ min(x, y)}
{P1 ∧ P2 ∧ i ≥ min(x, y) ∧ j ≥ min(x, y)}
r := min(x, y)
{r ≤ |A| ∧ (∀k. 0 ≤ k < r ⇒ A[k] ≤ 0) ∧ (r < |A| ⇒ A[r] > 0)}

P1 = x ≤ |A| ∧ (∀k. 0 ≤ k < i ∧ k even ⇒ A[k] ≤ 0) ∧ i even ∧ (x < |A| ⇒ A[x] > 0)
P2 = y ≤ |A| ∧ (∀k. 0 ≤ k < j ∧ k odd ⇒ A[k] ≤ 0) ∧ j odd ∧ (y < |A| ⇒ A[y] > 0)
448
Section 24

Rely-Guarantee

449
Motivation
• Owicki-Gries is not compositional
• generalise it to make it compositional

{P } c ∥ E {Q}

/⃝ +3 ⃝ /Q
7? ⃝

P /⃝ c +3 ⃝ /⃝ /⃝ c +3 ⃝ /⃝ /⃝ +3 ⃝ /⃝ +3 Q
#
⃝ +3 ⃝ /⃝ +3 Q

450
Motivation

P
∗ /⃝ c +3 ⃝ ∗ /⃝ c +3 ⃝ ∗ /Q


−→: any state transition that can be done by any other thread, repeated zero or more
times

451
Rely-Guarantee

{P, R} c {G, Q}

If
• the initial state satisfies P , and
• every state change by another thread satisfies the rely condition R,
and
then c is executed and terminates,

then
• every final state satisfies Q, and
• every state change in c satisfies the guarantee condition G.

452
Rely-Guarantee – Parallel Rule

{P1 , R ∨ G2 } c1 {G1 , Q1 } {P2 , R ∨ G1 } c2 {G2 , Q2 }


{P1 ∧ P2 , R} c1 ∥ c2 {G1 ∨ G2 , Q1 ∧ Q2 }

453
Rely-Guarantee – Consequence Rule

R ⇒ R′ {P, R′ } c {G′ , Q} G′ ⇒ G
{P, R} c {G, Q}

Note: both rules can be packed in a single rule.

454
From Floyd-Hoare to Rely-Guarantee

{P } c {Q} ???
{P, R} c {G, Q}

R R R R R
{
{

{
{
{
P /P /P +3 Q /Q /Q /Q
{

455
Back to Stores

{P } c {Q} P stable under R Q stable under R c is contained in G


{P, R} c {G, Q}

P stable under R: ∀s, s′ . P (s) ∧ R(s, s′ ) =⇒ P (s′ )


c contained in G: ∀s, s′ . P (s) ∧ (s, s′ ) ∈ C[[c]] =⇒ G(s, s′ )

456
Making Assertions Stable

Assume

R = (x 7→ n ⇝ x 7→ n − 1)
= {(s, s′ ) | ∃n. s(x) = n ∧ s′ (x) = s + {x 7→ n − 1}}
G = (x 7→ n ⇝ x 7→ n + 1)
= {(s, s′ ) | ∃n. s(x) = n ∧ s′ (x) = s + {x 7→ n + 1}}

{x == 2, R} x := x + 1 {G, x == 3}

457
Making Assertions Stable

Assume

R = (x 7→ n ⇝ x 7→ n − 1)
= {(s, s′ ) | ∃n. s(x) = n ∧ s′ (x) = s + {x 7→ n − 1}}
G = (x 7→ n ⇝ x 7→ n + 1)
= {(s, s′ ) | ∃n. s(x) = n ∧ s′ (x) = s + {x 7→ n + 1}}

{x ≤ 2, R} x := x + 1 {G, x ≤ 3}

458
FindFirstPositive
i := 0 ; j := 1 ; x := |A| ; y := |A| ;
{P1 ∧ P2 }
{P1 , G2 } {P2 , G1 }
while i < min(x, y) do while j < min(x, y) do
{P1 ∧ i < x ∧ i < |A|}
...
∥ {P2 ∧ j < y ∧ j < |A|}
...
{P1 } {P2 }
{G1 , P1 ∧ i ≥ min(x, y)} {G2 , P2 ∧ j ≥ min(x, y)}

{P1 ∧ P2 ∧ i ≥ min(x, y) ∧ j ≥ min(x, y)}


r := min(x, y)
{r ≤ |A| ∧ (∀k. 0 ≤ k < r ⇒ A[k] ≤ 0) ∧ (r < |A| ⇒ A[r] > 0)}

P1 = x ≤ |A| ∧ (∀k. 0 ≤ k < i ∧ k even ⇒ A[k] ≤ 0) ∧ i even ∧ (x < |A| ⇒ A[x] > 0)
P2 = y ≤ |A| ∧ (∀k. 0 ≤ k < j ∧ k odd ⇒ A[k] ≤ 0) ∧ j odd ∧ (y < |A| ⇒ A[y] > 0)
G1 = {(s, s′ )|s′ (y) = s(y) ∧ s′ (j) = s(j) ∧ s′ (x) ≤ s(x)}
G2 = {(s, s′ )|s′ (x) = s(x) ∧ s′ (i) = s(i) ∧ s′ (y) ≤ s(y)}
459
Rely-Guarantee Abstraction

Forgets
• which thread performs the action
• in what order the actions are performed
• how many times the action is performed
Usually, this is fine. . .

460
Verify This
{x == 0}

{x == 0 ∨ x == 1} {x == 0 ∨ x == 1}

x := x + 1 ∥ x := x + 1

{x == 1 ∨ x == 2} {x == 1 ∨ x == 2}

{x == 2}

G1 , G2 = (x 7→ n ⇝ x 7→ n + 1)

461
Verify This
{x == 0}

{∃n ≥ 0. x 7→ n, G2 } {∃n ≥ 0. x 7→ n, G1 }

x := x + 1 ∥ x := x + 1

{G1 , ∃n ≥ 1. x 7→ n} {G2 , ∃n ≥ 1. x 7→ n}

{∃n ≥ 1. x 7→ n}

G1 , G2 = (x 7→ n ⇝ x 7→ n + 1)

462
From Floyd-Hoare to Rely-Guarantee (recap)

{P } c {Q} ???
{P, R} c {G, Q}
P stable under R if and only if {P } R∗ {P }

R R R R R
{
{

{
{
{
P /P /P +3 Q /Q /Q /Q
{

463
Section 25

Conclusion

464
Learning Outcome I

1. Understand the role of theoretical formalisms,


such as operational and denotational semantics

▶ IMP language
▶ operational semantics
▶ denotational semantics
▶ axiomatic semantics
▶ functions
(call-by-name, call-by-value)
▶ references
▶ extensions
(data structures, error handling, object-orientation,. . . )

465
Learning Outcome II

2. Apply these semantics in the context of programming languages

▶ IMP language + extensions


▶ configurations
▶ derivations
▶ transitions

466
Learning Outcome III

3. Evaluate differences (advantages/disadvantages) of these


theoretical formalisms

▶ small-step vs big-step
▶ operational vs denotational vs axiomatic (vs algebraic)

467
Learning Outcome IV

4. Create operational or denotational semantics of simple imperative


programs

▶ IMP + extensions + types


▶ derivations
▶ transitions

468
Learning Outcome V

5. Analyse the role of types in programming languages

▶ types
▶ subtypes
▶ progress and preservation properties
▶ Curry-Howard correspondence

469
Learning Outcome VI

6. Formalise properties and reason about programs

▶ Isabelle/HOL
▶ semantic equivalences
▶ decorated programs
▶ Floyd-Hoare logic, wlp
▶ Owicki-Gries, Rely-Guarantee

470
Learning Outcome VII

7. Apply basic principles for formalising concurrent programming


languages

▶ Guarded Command Language


▶ process algebra
(value-passing CCS and pure CCS)
▶ semantic equivalences
▶ Owicki-Gries, Rely-Guarantee

471
Learning Outcome VIII

8. Additional Outcomes

▶ structural induction
▶ substitution
▶ ...

472
We covered A LOT

. . . but that’s only the tip of the iceberg

473
The Message I

Good language design?


• precise definition of what the language is
(so can communicate among the designers)
• technical properties
(determinacy, decidability of type checking, etc.)
• pragmatic properties
(usability in-the-large, implementability)

(that’s also an answer to LO1)

474
The Message II

What can you use semantics for?


• to understand a particular language
▶ what you can depend on as a programmer
▶ what you must provide as a compiler writer
• as a tool for language design:
▶ for clean design
▶ for expressing design choices, understanding language features and
how they interact
▶ for proving properties of a language, eg type safety, decidability of type
inference.
• as a foundation for proving properties of particular programs
verified software

475
Trend: Verified Software
• increasingly important
• “rough consensus and running code” (trial and error)
is not sufficient
• develop operational models of real-world languages/applications

• progress in verification makes it possible


build end-to-end verified systems

▶ formal semantics for (a large subset of C) [see M. Norrish]


▶ CompCert/CakeML: verified compilers
(full compiler verified in Coq/HOL4)
▶ seL4: high-assurance, high-performance operating system microkernel
(proofs in Isabelle/HOL)
▶ formal semantics for hardware (PPC, x86, ARM)

476
Are We Done
• more ‘standard’ features
▶ dependent types
▶ continuations
▶ lazy evaluation
▶ side effects

• more support for separation of concerns


▶ low-level features, such as memory models
▶ high-level features, such as broadcast

• more applications
▶ optimisations
▶ code generation

477
More Features – Dependent Types

• having “compile-time” types that depend on “run-time” values


• can avoid out-of-bounds errors

478
More Features – Dependent Types

example: typing Lists with Lengths

non-dependant type for list (similar to trees)


nil : IList
cons : int → IList → IList
hd : IList → int
tl : IList → IList
isnil : IList → bool

479
More Features – Dependent Types

Example: Typing Lists with Lengths

dependant type for list (carry around length)


nil : IList 0
cons : Πn:nat. int → (IList n) → (IList (succ n))
hd : Πn:nat. (IList (succ n)) → int
tl : Πn:nat. (IList (succ n)) → (IList n)
isnil :

480
More Features – Dependent Types
Example: typing lists with lengths
• using and checking dependent types

(fn n : nat ⇒ (fn l : IList(succ (succ n)) ⇒


(hd (succ n) l)+
(hd n (tl (succ n) l))
))

• propositions as dependent types


(Curry–Howard lens)

get : Πm : nat. Πn : nat. (Less m n) → (IList n) → int

481
More Feature – Hardware Model

Fundamental Question

What is the behaviour of memory?


• . . . at the programmer abstraction
• . . . when observed by concurrent code

482
More Feature – Hardware Model

First Model: Sequential Consistency

Multiple threads acting on a sequentially consistent (SC) shared


memory:
the result of any execution is the same as if the operations of
all the processors were executed in some sequential order, re-
specting the order specified by the program
[Lamport, 1979]

483
More Feature – Hardware Model

⟨(skip ∥ (l := 7 + !l) , {l 7→ 1}⟩


r /• +
/• w / ⟨(skip ∥ (skip , {l 7→ 8}⟩
5
w

⟨(l := 1) ∥ (l := 7 + !l) , {l 7→ 0}⟩ ⟨skip ∥ (l := 7 + 0) , {l 7→ 1}⟩


5 6
+ r w +

) '
⟨(l := 1 + 0) ∥ (l := 7 + !l) , {l 7→ 0}⟩ ⟨(l := 1) ∥ (l := 7 + 0) , {l 7→ 0}⟩ ⟨skip ∥ (l := 7) , {l 7→ 1}⟩
w / ⟨skip ∥ skip , {l 7→ 7}⟩
4 5 7
r r + + w

) (
⟨(l := 1 + !l) ∥ (l := 7 + !l) , {l 7→ 0}⟩ ⟨(l := 1 + 0 ∥ (l := 7 + 0) , {l 7→ 0}⟩ ⟨(l := 1) ∥ (l := 7) , {l 7→ 0}⟩
5 6
r r + + w

* ) '
⟨(l := 1 + !l) ∥ (l := 7 + 0) , {l 7→ 0}⟩ ⟨(l := 1 + 0) ∥ (l := 7) , {l 7→ 0}⟩ ⟨(l := 1) ∥ skip , {l 7→ 7}⟩
w / ⟨skip ∥ skip , {l 7→ 1}⟩
5 7
+ r w +

) (
⟨(l := 1 + !l) ∥ (l := 7) , {l 7→ 0}⟩ ⟨(l := 1 + 0) ∥ skip , {l 7→ 7}⟩
w

)
⟨(l := 1 + !l) ∥ skip , {l 7→ 0}⟩
r /• +
/• w / ⟨(skip ∥ (skip , {l 7→ 8}⟩

484
More Feature – Hardware Model

• implement naive mutual exclusion


• specify concepts such as “atomic”
(see GCL)
• but on x86 hardware you have these behaviours
▶ hardware busted?
▶ program bad?
▶ model is wrong?

SC is not a good model of x86 (or of Power, ARM, Sparc, Itanium. . . )

485
More Feature – Hardware Model
New problem?

No: IBM System 370/158MP in 1972, already non-SC

486
More Feature – Hardware Model
But still a research question

• mainstream architectures and languages are key interfaces


• . . . but it is been very unclear exactly how they behave

• more fundamentally:
▶ it has been (and in significant ways still is) unclear how we can specify
that precisely
▶ if we can do that, we can build on top:
explanation, testing, emulation, static/dynamic analysis,
model-checking, proof-based verification,. . .

487
More Features – Broadcast

Motivation:
model communication
• network protocols
• communication protocols
• ...

488
Broadcast in CCS α α
α P −→ P ′ Q −→ Q′
α.P −→ P α α
P + Q −→ P ′ P + Q −→ Q′
η c c̄ η
P −→ P ′ P −→ P ′ , Q −→ Q′ Q −→ Q′
η τ η
P |Q −→ P ′ |Q P |Q −→ P ′ |Q′ P |Q −→ P |Q′
ℓ ℓ ℓ
P −→ P ′ P −→ P ′ P −→ P ′ def

(c̸=ℓ̸=c̄) ℓ
(A = P )
f (ℓ)
P [f ] −→ P ′ [f ] P \c −→ P ′ \c A −→ P′

b♯1 b? b♯1 b♯2 b? b♯2


P −→ P ′ , Q −→
X P −→ P ′ , Q −→ Q′ P −→,
X Q −→ Q′
b♯1 b♯ b♯2
P |Q −→ P ′ |Q P |Q −→ P ′ |Q′ P |Q −→ P |Q′
◦ ! ?
♯1 ◦♯2 =♯̸= with ! !
? ! ?

489
Broadcast in CCS

• parallel composition associative, commutative?


• all operators are a congruence?

490
Case Study: AODV
Ad Hoc On-Demand Distance Vector Protocol
• routing protocol for wireless mesh networks
(wireless networks without wired backbone)

• ad hoc (network is not static)


• on-Demand (routes are established when needed)
• distance (metric is hop count)

• developed 1997–2001 by Perkins, Beldig-Royer and Das


(University of Cincinnati)

• one of the four protocols standardised by the IETF MANET working


group (IEEE 802.11s)

491
Case Study: AODV
Main Mechanism
• if route is needed
BROADCAST RREQ
• if node has information about a destination
UNICAST RREP
• if unicast fails or link break is detected
GROUPCAST RERR

• performance improvement via


intermediate route reply

492
Case Study: AODV
Formal Specification Language (Process Algebra)

493
Case Study: AODV
Specification

494
Case Study: AODV
Full specification of AODV (IETF Standard)

Specification details
• around 5 types and 30 functions
• around 120 lines of specification
(in contrast to 40 pages English prose)

Properties of AODV
route correctness ✓
loop freedom ✓ (for some interpretations)
route discovery ✗
packet delivery ✗

495
Final Oral Exam

• 6–10 November, 2021


• 30 minutes oral examination
• read the guidelines (available via course webpage)
• send through the signed statement in time

GOOD LUCK

496
Feedback

Please provide feedback

• types of possible feedback


▶ suggestions
▶ improvements
• send feedback
▶ SELT
▶ to me (orally, written)

497
The ‘Final’ Slide

• Q/A sessions
▶ Thursday, November 2 (11am-12pm),
Marie Reay room 5.02
▶ topics: all questions you prepare
▶ no questions, no session

• I hope you. . .
▶ had some fun (I had),
even despite the challenging times
▶ learnt something useful

498
COMP3610/6361 done – what’s next?

• COMP3630/6363 (S1 2024)


Theory of Computation

• COMP4011/8011 (S2 2022)


Special Topic: Software Verification using Proof Assistants

• Individual Projects/Honour’s Theses/PhD projects . . .


(potentially casual jobs)

499
Logic Summer School
December 04 – December 15, 2021

Lectures include
• Fundamentals of Metalogic
(John Slaney, ANU)
• Defining and Reasoning About Programming Languages
(Fabian Muehlboeck, ANU)
• Propositions and Types, Proofs and Programs
(Ranald Clouston, ANU)
• Gödel’s Theorem Without Tears
(Dominik Kirst, Ben-Gurion University)
• Foundations for Type-Driven Probabilistic Modelling
(Ohad Kammar, U Edinburgh)
• ...

Registration is A$150

http://comp.anu.edu.au/lss
500
— THE END —

501
Section 27

Add-On
Program Algebras:
Floyd-Hoare Logic meets Regular Expressions

502
Motivation

• CCS and other process algebra yield algebraic expressions, e.g.


a.b.nil + c.nil
• they also give rise to algebraic (semantic) equalities, e.g.
a.nil + a.nil = a.nil
• but how does algebra relate to Hoare triples

503
Beyond Floyd-Hoare Logic

some ‘optimisations’ are not possible within Floyd-Hoare logic

{P } if b then c else c {Q}


{P } c {Q}

(trivially) unprovable in Floyd-Hoare logic

504
Trace Model – Intuition
a program can be interpreted as set of program runs/traces

sets of traces s0 c1 s1 c2 . . . sn−1 cn1 sn

A ⊆ Σ × (Act × Σ)∗

non-deterministic choice A∪B


sequential composition AB =S{asb | xs ∈ A ∧ sb ∈ B}
iteration A∗ = n≥0 = A0 ∪ A1 ∪ A2 . . .
skip 1 = Σ (all traces of length 0)
fail/abort 0=∅

505
Guarded Commands – Intuition

a program can be interpreted as set of guarded commands

sets of guarded strings α0 c1 α1 c2 . . . αn−1 cn1 αn


(α, β, . . . Boolean expressions)

non-deterministic choice A∪B


sequential composition AB =S{aαb | xα ∈ A ∧ αb ∈ B}
iteration A∗ = n≥0 = A0 ∪ A1 ∪ A2 . . .
skip 1 = {all Boolean expressions}
fail/abort 0=∅

506
Properties

• associativity: a(bc) = (ab)c


• neutrality: 1a = a = a1
• distributivity: (a + b)c = ac + bc
a(b + c) = ab + ac (?)
• absorption: 0a = 0 = a0
• iteration: (ab)∗ a = a(ba)∗

507
Regular expressions

we know these rules from regular expressions, finite automata and


formal languages

508
Kleene Algebra (KA)
is the algebra of regular expressions
(traces/guarded commands without ‘states’)

Examples
• ab + ba
{ab, ba}

• (ab)∗ a = a(ba)∗
{a, aba, ababa, . . . }

• (a + b)∗ = (a∗ b)∗ a∗


{all strings over a,b}

509
Regular Sets – Intuition

regular sets over Σ

non-deterministic choice (+, |) A∪B


sequential composition AB =S{ab | x ∈ A ∧ b ∈ B}
iteration A∗ = n≥0 = A0 ∪ A1 ∪ A2 . . .
neutral 1 = {ε}
(language containing the empty word)
empty language 0=∅

510
Axioms of Kleene Algebra
A Kleene algebra is a structure (K, +, ·, 0, 1,∗ ) such that
• K is an idempotent semiring under +, ·, 0, 1
(a + b) + c = a + (b + c) (a, ·b) · c = a · (b · c)
a+b=b+a a·1=1·a=a
a+a=a a·0=0·a=0
a+0=a
a · (b + c) = a · b + a · c
(a + b) · c = a · c + b · c
• a∗ b = least x such that b + ax ≤ x
• ba∗ = least x such that b + xa ≤ x

x≤y ⇔x+y =y
multiplication symbol is omitted

511
Characterising Iteration
• complete semiring/quantales (suprema exist)

a∗ = Σn≥0 an
supremum with respect to ≤

• Horn axiomatisation
▶ a∗ b = least x such that b + ax ≤ x:

1 + aa∗ ≤ a∗
b + ax ≤ x ⇒ a∗ b ≤ x

▶ ba∗ = least x such that b + xa ≤ x:

1 + a∗ a ≤ a∗
b + ax ≤ x ⇒ ba∗ ≤ x

512
Models & Properties

regular expressions, traces and guarded strings form Kleene algebras

abstract laws: (ab)∗ a ≤ a(ba)∗


(proof is a simple exercise)

applies to all models

guarded strings/commands have more structure (assertions)

513
Kleene Algebra with Tests (KAT)

A Kleene algebra with tests is a structure (K, B, +, ·,∗ , ¬, 0, 1), such that
• (K, +, ·,∗ , 0, 1) is a Kleene algebra
• (B, +, ·, ¬, 0, 1) is a Boolean algebra
• B⊆K

• a, b, c, . . . range over K
• p, q, r, . . . range over B

514
Kleene Algebra with Tests (KAT)

+, ·, 0, 1 serve double duty


• applied to programs, denote choice, composition, fail, and skip, resp.
• applied to tests, denote disjunction, conjunction, falsity, and truth,
resp.
• these usages do not conflict

pq = p ∧ q p+q =p∨q

515
Models

• Trace models
K: sets of traces s0 c1 s1 c2 . . . sn−1 cn1 sn
B: sets of traces of length 0
• Language-theoretic models K: sets of guarded strings
α0 c1 α1 c2 . . . αn−1 cn1 αn
B: atoms of a finite free Boolean algebra

516
Modelling Programs
[Fischer & Ladner 79]

• a ; b = ab
• if p then a else c = pa + ¬pc
• while p do c = (pc)∗ ¬p

517
Floyd-Hoare Logic vs KAT

Theorem
KAT subsumes propositional Floyd-Hoare logic (PHL)
(Floyd-Hoare logic without assignment rule)

{p} c {q} modeled by pc = pcq (or pc¬q = 0, or pc¬q ≤ 0)

518
Floyd-Hoare logic

{p} a {q} {q} b {r}


pa¬q = 0 ∧ qb¬r = 0 =⇒ pab¬r = 0
{p} ab {r}

{p ∧ r} a {q} {p ∧ ¬r} b {q}


pra¬q = 0 ∧ p¬rb¬q = 0 =⇒ p(ra + ¬rb)¬q = 0
{p} if r then a else b {q}

{p ∧ r} a {p}
pra¬p = 0 =⇒ p(ap)∗ ¬(¬rp) = 0
{p} while r do a {¬r ∧ p}

519
Crucial Theorems

Theorem
These are all theorems of KAT
(proof is an exercise)

Theorem (Completeness Theorem)


All valid rules of the form
{p1 } c1 {q1 } . . . {pn } cn {qn }
{p} c {q}

are derivable in KAT (not so in PDL)

520
Advantages of Kleene Algebra

• unifying approach
• equational reasoning + Horn clauses
some decidability & automation
• but, missing out assignment rule of Floyd-Hoare logic

521
Other Applications of KA(T)
There are more applications
• automata and formal languages
▶ regular expressions
• relational algebra
• program logic and verification
▶ dynamic Logic
▶ program analysis
▶ optimisation
• design and analysis of algorithms
▶ shortest paths
▶ connectivity
• others
▶ hybrid systems
▶ ...

522
Rely-Guarantee Reasoning
Hoare triple
{p} c {q} ⇔ pc¬q = 0

But what about {P, R} c {G, Q}?

{p, aR } c {bG , q} ⇔ {p} aR ∥ c {q} ∧ c ≤ bG


⇔ p(aR ∥ c)¬q = 0 ∧ c ≤ bG

needs algebra featuring parallel (we have seen one)


• R ∥ (S + T ) = R ∥ S + R ∥ T

• R ∥ (S · T ) = (R ∥ S) · (R ∥ T )

• R ∥ (S ∥ T ) = (R ∥ S) ∥ (R ∥ T )

523
Rely-Guarantee Reasoning
Hoare triple
{p} c {q} ⇔ pc¬q = 0

But what about {P, R} c {G, Q}?

{p, aR } c {bG , q} ⇔ {p} aR ∥ c {q} ∧ c ≤ bG


⇔ p(aR ∥ c)¬q = 0 ∧ c ≤ bG

needs algebra featuring parallel (we have seen one)


• R ∥ (S + T ) = R ∥ S + R ∥ T

• R ∥ (S · T ) = (R ∥ S) · (R ∥ T )

• R ∥ (S ∥ T ) = (R ∥ S) ∥ (R ∥ T )

524

You might also like