SLIDE 1 3BA31 Formal Methods 1
VDM♣
“VDM” stands for the Vienna Development Method — Result of work the in the Vienna Research Laboratory of IBM (1960s). VDM is now a standardised formal-method (VDM-SL — Specification Language):
- reasoning based on the Logic of Partial Functions (LPF)
- based on the notion of specifiying programs via pre- and post-condition predicates.
- http://en.wikipedia.org/wiki/Vienna Development Method
VDM♣ is a non-standard dialect of VDM:
- based on equational reasoning, rather than LPF.
- uses pre-condition predicates, but most specifications give an abstract definition of the computed
result (called explicit post-conditions in VDM-SL)
- http://www.cs.tcd.ie/Andrew.Butterfield/IrishVDM/
The way in which the mathematics is used to reason about systems is very similar in both VDM-SL and VDM♣.
3BA31 Formal Methods 2
The “Method” in VDM♣: Requirements
- capture the “users” expectations of the behaviour of the system to be built.
- model of the environment, or the “World”.
- model of the desired interactions between system and environment
- This process requires building a model of the problem domain, and is often referred to as Domain
Modelling or Domain Capture.
SLIDE 2 3BA31 Formal Methods 3
The “Method” in VDM♣: Specifications
- a description of the behaviour the system must have in order to satisfy the requirements.
- a model of the system to be built
- the process of ensuring that a specification is consistent w.r.t the requirements is called Validation
The VDM method says relatively little about validation, as this is very probelm-specific. VDM methodology does ensure that the specification makes sense, (even it if not what the users wanted !). VDM/VDM♣ uses its mathematics to model the pertinent parts of the system and environment (as state) and then specifies the safety conditions and operations that the system must maintain and provide. System = State + Operations
3BA31 Formal Methods 4
The “Method” in VDM♣
In order to produce a formal model according to the Vienna Development Method, we need to:
- Determine the System State
– State Type – State Invariant – Initial State
– Operation Pre-Condition – Operation Post-Condition
- Discharge all Proof Obligations
SLIDE 3 3BA31 Formal Methods 5
The “Method” in VDM♣: Proof Obligations
- Proof obligation is a required property of a VDM model.
- Typically capture idea that model “makes sense”.
- Method compliance the successful proof of every Proof Obligation.
- They don’t guarantee that what a model is realistic, or what the “customer” wanted.
Note: In addition to the method proof obligations, we may want to prove that other properties hold, related to our particular application.
3BA31 Formal Methods 6
The “Method” in VDM♣: System State
System state contains all the relevant values and conditions of the system. We define it by first declaring its components and their structure, using the types and type constructors of VDM♣:
Σ ∈ State = (expression using N, B, . . . , ×, P, → , →,
m
→ , . . . , ADTs)
Relationships and conditions of the state that always hold true (often called safety properties) are captured by an invariant: inv-State
: State → B
inv-State Σ
. . .
Proof Obligation: State Invariant Satisfiability: We must prove that the invariant is satisfiable, i.e there is at least one instance of the state datatype that satisfies it.
∃ Σ : State • inv-State Σ
SLIDE 4 3BA31 Formal Methods 7
The “Method” in VDM♣: Initial State
We generally need to introduce the notion of an initial or starting state, at least of any system we are proposing to build:
Σ0 : State Σ0
. . .
Proof Obligation: Initial-State Invariant: We must prove that the initial state satisfies the invariant: inv-State Σ0 = TRUE Note that a proof of this obligation is also a proof of the Invariant Satisfiability obligation (why?)
3BA31 Formal Methods 8
The “Method” in VDM♣: Operations
- Capture events that change or observe the system state
– initiated by the system, or – by the environment.
- Have inputs and outputs
- cause state changes
- Two main classes of operations:
– state change: no outputs, but state changes – state enquiry: outputs, but state is unchanged An operation with outputs that changes state as well, can be decomposed into two operations, on of each of the above classes. We shall assume all operators have been so decomposed.
SLIDE 5 3BA31 Formal Methods 9
The “Method” in VDM♣: State Change
State change operations take input or control parameters of some type (c ∈ Control) and produce a change in state. When specifying such (called StChg, say), we need to identify the circumstances under which we consider the operator to be well-defined — the precondition of the operation. We capture this by a declaration with the following signatures and forms: StChg
: Control → State → State
StChg[c]Σ
expression defining after-State pre-StChg
: Control → State → B
pre-StChg[c]Σ
predicate describing pre-condition Proof Obligation: State Change Invariant We must prove that if the state before change satisfies the invariant, and the pre-condition of the
- perator holds, that then the invariant holds after the operation has run:
inv-State Σ ∧ pre-StChg[c]Σ ⇒ inv-State(StChg[c]Σ)
3BA31 Formal Methods 10
The “Method” in VDM♣: State Query
State query operations take input or query parameters of some type (q ∈ Query), look at the state, and return an appropriate result value (r ∈ Result) . When specifying such (called StQry, say), we need to identify the circumstances under which we consider the operator to be well-defined — the precondition of the operation. We capture this by a declaration with the following signatures and forms: StQry
: Query → State → Result
StQry[q]Σ
expression defining query-result pre-StQry
: Query → State → B
pre-StQry[q]Σ
predicate describing pre-condition There is no specific proof obligation associated with queries, other than the general observation that a query’s result need not be defined or make sense if the pre-condition does not hold.
SLIDE 6 3BA31 Formal Methods 11
Scribbles 4 : Example Model — Orienteering Event
We construct a model of an orienteering event, for competitors using the SportIdent (SI) System. We first introduce the Types: s ∈ SI
= N
SI (Competitor) Numbers c ∈ Control
= N
Control Numbers r ∈ Course given set of course identifiers A course has a non-empty list of controls:
κ ∈ Courses =
Course
m
→ CONTROL+
A competitor enters a course:
ω ∈ Entries =
SI
m
→ Course
A competitor runs and collects controls in order (hopefully):
ω ∈ Runs =
SI
m
→ Control∗
3BA31 Formal Methods 12
Scribbles 4 : Orienteering State and Invariant
System state is comprised of Courses, Entries and Runs:
(κ, ω, ρ) ∈ OState
Courses × Entries × Runs Competitors can only enter courses that are offered (1), and when running must be entered (2), and can only find controls that are out there (3): inv-OState(κ, ω, ρ)
rng ω ⊆ dom κ
(1)
∧ dom ρ ⊆ dom ω
(2)
∧ controlsof(ρ) ⊆ controlsof(κ)
(3) controlsof
: (A
m
→ P B) → P B
controlsof(α)
∪/(Pelems(rng α))
controlsof
=
∪/ ◦ Pelems ◦ rng
SLIDE 7 3BA31 Formal Methods 13
Scribbles 4 : Orienteering Initial State
Initially everything is empty: O0
:
OState O0
(θ, θ, θ)
This satisfies the invariant, and so we discharge two proof obligations: inv-OState(θ, θ, θ)
= rng θ ⊆ dom θ ∧ dom θ ⊆ dom θ ∧ controlsof(θ) ⊆ controlsof(θ) = ∅ ⊆ ∅ ∧ ∅ ⊆ ∅ ∧ ∅ ⊆ ∅ =
TRUE controlsof(θ)
=
∪/(Pelems(rng θ))
=
∪/(Pelems(∅)
=
∪/(∅)
= ∅
3BA31 Formal Methods 14
Scribbles 4 : Planning An Event
We now introduce an operation to allow the planner to add a course, and we decide to impose no pre-condition, to allow the planner flexibility to change things: Plan
: (Course × Controls+) → OState → OState
Plan(r, σ)(κ, ω, ρ)
(κ † {r → σ}, ω, ρ)
pre-Plan
: (Course × Controls+) → OState → B
pre-Plan(r, σ)(κ, ω, ρ)
TRUE
SLIDE 8
3BA31 Formal Methods 15
Scribbles 4 : Plan Proof Obligation
We have to show that operation Plan preserves the invariant, when its pre-condition holds: inv-OState(κ, ω, ρ) ∧ pre-Plan(r, σ)(κ, ω, ρ) ⇒ inv-OState(Plan(r, σ)(κ, ω, ρ)) As the pre-condition is vacuously true, we can drop it: inv-OState(κ, ω, ρ) ⇒ inv-OState(Plan(r, σ)(κ, ω, ρ))
3BA31 Formal Methods 16
Mini-Exercise 2
Does Plan preserve the invariant ? inv-OState(κ, ω, ρ) ⇒ inv-OState(Plan(r, σ)(κ, ω, ρ)) If you think so, give an informal argument as to why. If you think not, give a counter-example showing what goes wrong Due: at start of 12noon Lecture, Thursday, February 15th, 2007.
SLIDE 9 3BA31 Formal Methods 17
Mini-Exercise 1
Show that
2 + 2
β
→ 4
Hints:
- 1. Use rightmost-innermost reduction order here.
- 2. You might want to pull an inner redex out, do the reduction separately, and then plug the result
back in.
β
→ 2 as a warm-up!
Due: at start of 12noon Lecture, Thursday, February 15th, 2007.
3BA31 Formal Methods 18
Mini-Solution 1 2 + 2 =
PLUS 2 2
= (λ m n s z • m s (n s z)) (λ s z • s(s z)) (λ s z • s(s z))
β
→ (λ n s z • (λ s z • s(s z)) s (n s z)) (λ s z • s(s z))
β
→ λ s z • (λ s z • s(s z)) s ((λ s z • s(s z)) s z)
β
→ λ s z • (λ s z • s(s z)) s ((λ z • s(s z)) z)
β
→ λ s z • (λ s z • s(s z)) s (s(s z))
β
→ λ s z • (λ z • s(s z)) (s(s z))
β
→ λ s z • s(s(s(s z))) = 4
SLIDE 10 3BA31 Formal Methods 19
Mini-Exercise 2
Does Plan preserve the invariant ? inv-OState(κ, ω, ρ) ⇒ inv-OState(Plan(r, σ)(κ, ω, ρ)) If you think so, give an informal argument as to why. If you think not, give a counter-example showing what goes wrong Due: at start of 12noon Lecture, Thursday, February 15th, 2007.
3BA31 Formal Methods 20
Mini-Solution 2
We’ll do this backwards:
- 1. Attempt a Proof
- 2. Test it using QuickCheck
- 3. Think about the Issue
We should really approach this the other way around!
SLIDE 11
3BA31 Formal Methods 21
Mini-Solution 2: Proof Attempt (I)
To Prove: inv-OState(κ, ω, ρ) ⇒ inv-OState(Plan(r, σ)(κ, ω, ρ)) Strategy: we assume the antecedent: inv-OState(κ, ω, ρ) in order to show the truth of the consequent: inv-OState(Plan(r, σ)(κ, ω, ρ))
3BA31 Formal Methods 22
Mini-Solution 2: Proof Attempt (II)
We assume (A1)–(A3′), expanding definitions of inv-OState and controlsof:
(A1) rng ω ⊆
dom κ
(A2)
dom ρ
⊆
dom ω
(A3)
controlsof(ρ)
⊆
controlsof(κ)
(A3′)
∪/(Pelems(rng ρ)
⊆
∪/(Pelems(rng κ)
to show inv-OState(Plan(r, σ)(κ, ω, ρ))
SLIDE 12
3BA31 Formal Methods 23
Mini-Solution 2: Proof Attempt (III)
inv-OState(Plan(r, σ)(κ, ω, ρ))
≡
“ definition of Plan ” inv-OState(κ † {r → σ}, ω, ρ)
≡
“ definition of inv-OState ”
rng ω ⊆ dom (κ † {r → σ}) ∧ dom ρ ⊆ dom ω ∧ controlsof(ρ) ⊆ controlsof(κ † {r → σ}) ≡
“ property of dom and † ”
rng ω ⊆ dom κ ∪ { r } ∧ dom ρ ⊆ dom ω ∧ controlsof(ρ) ⊆ controlsof(κ † {r → σ})
3BA31 Formal Methods 24
Mini-Solution 2: Proof Attempt (IV) rng ω ⊆ dom κ ∪ { r } ∧ dom ρ ⊆ dom ω ∧ controlsof(ρ) ⊆ controlsof(κ † {r → σ}) ≡
“ Assumption A1 and S ⊆ T ⇒ S ⊆ T ∪ U, Assumption A2 ” TRUE ∧ TRUE
∧ controlsof(ρ) ⊆ controlsof(κ † {r → σ}) ≡
“ prop. calc., definition of controlsof ”
∪/(Pelems(rng ρ)) ⊆ ∪/(Pelems(rng(κ † {r → σ})))
≡
“ alternative form of override: µ †{a → b} = ⊳
−[a] µ ⊔{a → b} ”
∪/(Pelems(rng ρ)) ⊆ ∪/(Pelems(rng(⊳
−[r]κ ⊔ {r → σ})))
SLIDE 13
3BA31 Formal Methods 25
Mini-Solution 2: Proof Attempt (V)
∪/(Pelems(rng ρ)) ⊆ ∪/(Pelems(rng(⊳
−[r]κ ⊔ {r → σ}))) ≡
“ property of rng ”
∪/(Pelems(rng ρ)) ⊆ ∪/(Pelems(rng(⊳
−[r]κ) ∪ { σ }))) ≡
“ property/definition of Pf ”
∪/(Pelems(rng ρ)) ⊆ ∪/(Pelems(rng(⊳
−[r]κ)) ∪ { elems σ }) ≡
“ property/definition of ∪/ ”
∪/(Pelems(rng ρ)) ⊆ ∪/(Pelems(rng(⊳
−[r]κ))) ∪ { elems σ }
3BA31 Formal Methods 26
Mini-Solution 2: Proof Attempt (VI)
∪/(Pelems(rng ρ)) ⊆ ∪/(Pelems(rng(⊳
−[r]κ))) ∪ { elems σ }
Uh-Oh ! From (A3’) we can assume
∪/(Pelems(rng ρ)
⊆
∪/(Pelems(rng κ)
But while we are adding in elems σ, we are also potentially taking away whatever controls were mapped to beforehand by r (in term ⊳
−[r]κ).
SLIDE 14
3BA31 Formal Methods 27
Mini-Solution 2: QuickCheck Test (I)
We can encode the model in QuickCheck and test the property [Show Script]
3BA31 Formal Methods 28
Mini-Solution 2: QuickCheck Test (II)
The test fails!
Scribbles04> test planInvTest Falsifiable, after 1 tests: G [1] ({G|->[0]},{0|->G},{0|->[0]})
SLIDE 15
3BA31 Formal Methods 29
Mini-Solution 2: QuickCheck Test (III)
The invariant holds to start: inv-OState({G → 0}, {0 → G}, {0 → 0})
= rng {0 → G} ⊆ dom {G → 0} ∧ dom {0 → 0} ⊆ dom {0 → G} ∧ controlsof({0 → 0}) ⊆ controlsof({G → 0}) = { G } ⊆ { G } ∧ { 0 } ⊆ { 0 } ∧ { 0 } ⊆ { 0 } =
TRUE But not when we are done: inv-OState(Plan(G, 1)({G → 0}, {0 → G}, {0 → 0}))
=
inv-OState({G → 1}, {0 → G}, {0 → 0})
= rng {0 → G} ⊆ dom {G → 1} ∧ dom {0 → 0} ⊆ dom {0 → G} ∧ controlsof({0 → 0}) ⊆ controlsof({G → 1}) = { G } ⊆ { G } ∧ { 0 } ⊆ { 0 } ∧ { 0 } ⊆ { 1 } =
TRUE ∧ TRUE ∧ FALSE
3BA31 Formal Methods 30
Mini-Solution 2: Think About It
A little thought should lead to the following conclusion: The planner might change a course mid-event, removing some controls, at a point when a runner has already visited them. Nothing in the model said that the planning had to be complete when the event began running. How might we enforce this ?
SLIDE 16 3BA31 Formal Methods 31
Scribbles 5 : Properties of Maps µ †ν
⊳ −[dom ν] µ ⊔ν
dom(µ †nu)
= (dom µ) ∪ (dom ν) rng(µ †nu) = (rng µ) ∪ (rng ν)
Counter-example:
µ = {a → 1} rng µ = { 1 } ν = {a → 2} rng ν = { 2 } µ †ν = {a → 2} rng(µ †ν) = { 2 } rng µ ∪rng ν = { 1, 2 } { 2 } = { 1, 2 }
3BA31 Formal Methods 32
Scribbles 5 : Fixing Plan
The solution is a pre-condition that says that planning can go on as long as no-one has entered: pre-Plan(r, σ)(κ, ω, ρ)
ω = θ ∧ ρ = θ
Does this preserve the invariant? inv-OState(Σ) ∧ pre-Plan(r, σ)(Σ)
⇒
inv-OState(Plan(r, σ)(Σ)) Will controlsof(ρ) remain a subset of controlsof(κ)?
SLIDE 17
3BA31 Formal Methods 33
Scribbles 5 : Plan Invariant (Thinking)
As the entries and runs maps are empty, by the pre-condition, and planning never adds to them, the stay empty once planning has just finished. So controlsof(ρ) is always empty and hence a subset of controlsof(κ), no matter how often the planner comes back and changes his mind. It looks good.
3BA31 Formal Methods 34
Scribbles 5 : Plan Invariant (Testing)
We should run this through QuickCheck again [Script]:
Scribbles05> test planInvTest OK, passed 100 tests.
It passes (eventually).
SLIDE 18
3BA31 Formal Methods 35
Scribbles 5 : Plan Invariant (Proving–I)
We assume (A1)–(A4), expanding definitions of inv-OState and controlsof:
(A1) rng ω ⊆
dom κ
(A2)
dom ρ
⊆
dom ω
(A3)
controlsof(ρ)
⊆
controlsof(κ)
(A3′)
∪/(Pelems(rng ρ)
⊆
∪/(Pelems(rng κ)
(A4) ω = θ ∧ ρ = θ
to show inv-OState(Plan(r, σ)(κ, ω, ρ)) which by (A4) is the same as: inv-OState(Plan(r, σ)(κ, θ, θ))
3BA31 Formal Methods 36
Scribbles 5 : Plan Invariant (Proving–II)
inv-OState(Plan(r, σ)(κ, θ, θ))
≡
“ definition of Plan ” inv-OState(κ † {r → σ}, θ, θ)
≡
“ definition of inv-OState ”
rng θ ⊆ dom (κ † {r → σ}) ∧ dom θ ⊆ dom θ ∧ controlsof(θ) ⊆ controlsof(κ † {r → σ}) ≡
“ A null map has empty domain and range: dom θ = ∅ = rng θ ”
∅ ⊆ dom (κ † {r → σ}) ∧ ∅ ⊆ ∅ ∧ controlsof(θ) ⊆ controlsof(κ † {r → σ})
SLIDE 19 3BA31 Formal Methods 37
Scribbles 5 : Plan Invariant (Proving–III) ∅ ⊆ dom (κ † {r → σ}) ∧ ∅ ⊆ ∅ ∧ controlsof(θ) ⊆ controlsof(κ † {r → σ}) ≡
“ ∅ ⊆ S, any S, definitions of controlsof ” TRUE ∧ TRUE ∧ ∪/(Pelems(rng θ) ⊆ controlsof(κ † {r → σ})
≡
“ prop. calc., rngθ = ∅ ”
∪/(Pelems(∅) ⊆ controlsof(κ † {r → σ})
≡
“ prop. calc., Pf∅ = ∅ ”
∪/(∅) ⊆ controlsof(κ † {r → σ})
≡
“ ∪/∅ = ∅ ”
∅ ⊆ controlsof(κ † {r → σ}) ≡
“ ∅ ⊆ S, any S ” TRUE
Formal Methods 38
Scribbles 5 : Other Operations
Orienteers can enter for an offered course, and change their mind when not already out running: Register
:
SI × Course → OState → OState pre-Register(s, c)(κ, ω, ρ)
c ∈ dom κ ∧ s /
∈ dom ρ
Register(s, c)(κ, ω, ρ)
(κ, ω † {s → c}, ρ)
An orienteer can run once, once entered: Run
:
SI × Control∗ → OState → OState pre-Run(s, σ)(κ, ω, ρ)
s ∈ dom ω ∧ s /
∈ dom ρ
Run(s, σ)(κ, ω, ρ)
(κ, ω, ρ † {s → σ})
A competitor is complete if they got precisely the controls on their course: Complete
:
SI → OState → B Complete(s)(κ, ω, ρ)
κ(ω(s)) = ρ(s)
SLIDE 20 3BA31 Formal Methods 39
Haskell Features
We take a brief look at some important Haskell features:
- Lists
- Type Polymorphism
- ADTs (Abstract Data Types)
- Namespaces
- Function and Operator Fixity
3BA31 Formal Methods 40
Lists (I)
Lists are a major datatype in Haskell: Type We use the notation [t] to denote a list whose elements are of type t. Constructing Values There are two basic ways to define a list:
- We write the empty list as []. It has type [t] for any type t.
- Given an element x of type t and a list xs of type [t], we can stick the element on the front
(“cons-ing”), written x:xs — the infix colon : is the list constructor. Accessing Values There are two ways to get at the components of a list:
- Using functions null, head and tail
- Pattern matching on the two ways to build a list.
SLIDE 21
3BA31 Formal Methods 41
Lists (II)
Functions null, head and tail can be defined by pattern matching:
null [] = True null (x:xs) = False head (x:xs) = x tail (x:xs) = xs
Note that head and tail are partial, being undefined for the empty-list. The list enumeration notation [x1, x2, . . . , xn] is syntactic sugar for x1 : (x2 : (. . . (xn : []) . . .)) There are a long list of functions available for list manipulation —see the Haskell “Prelude”
http://haskell.org/onlinereport/standard-prelude.html.
3BA31 Formal Methods 42
Type Polymorphism (I)
Consider the list length function:
length [] = 0 length (x:xs) = 1 + length xs
What type does it have? [ DEMO: Taking List Lengths ]
SLIDE 22 3BA31 Formal Methods 43
Type Polymorphism (II)
The function length works with lists of any type, and returns an Integer:
length :: [t] -> Int.
This works because it does not manipulate the elements in any way, but simply counts them. Polymorphic (“many-shaped”) types are simply types with parts, represented by type variables, that can take on any type (Haskell uses letters a, b, c,. . . for these). E.g. function reverse ::
[t] -> [t] takes a list of any type and reverses it to give a list
3BA31 Formal Methods 44
Abstract Data Types (I)
We can build our own datatypes by describing them as a collection of Constructors that build a value
- f the type from other types.
General framework:
data MyType =
C1 t11 t12 · · · t1k1
|
C2 t21 t22 · · · t2k2 . . .
|
Cn tn1 tn2 · · · tnkn Here all the ki, for i ∈ 1 . . . n can be zero or more. This is read as declaring MyType to be either a C1 built from t11 through to t1k1, or a C2 built . . . The names MyType can appear as one of more of the tij (Recursive types allowed).
SLIDE 23
3BA31 Formal Methods 45
Abstract Data Types (II)
We can define functions on these by pattern-matching: f
::
MyType− > AnotherType f (C1 p11 p12 · · · p1k1)
=
what to do with C1 variant f (C2 p21 p22 · · · p2k2)
=
what to do with C2 variant . . . f (Cn pn1 pn2 · · · pnkn)
=
what to do with Cn variant Here pij is a pattern matching a value of type tij.
3BA31 Formal Methods 46
Abstract Data Types (III)
Example 1 - Days of the Week. All the ki can be zero:
data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun isWeekDay :: Day -> Bool isWeekDay Sat = False isWeekDay Sun = False isWeekDay _ = True
The pattern is a wildcard and matches anything. Patterns are tried in the order listed.
SLIDE 24
3BA31 Formal Methods 47
Abstract Data Types (IV)
Example 2 - Binary Tree of Integers
data BinTreeInt = LeafI Int | BranchI BinTreeInt Int BinTreeInt btiSize (LeafI _) = 1 btiSize (BranchI left _ right) = 1 + btiSize left + btiSize right
So the following is a value of type BinTreeInt
BranchI (LeafI 1) 2 (LeafI 3)
3BA31 Formal Methods 48
Abstract Data Types (V)
Example 2 - Binary Tree of anything We can put a type parameter (type variable) immediately after the name of our type, which can then be used as on of the tij.
data BinTree t = Leaf t | Branch (BinTree t) t (BinTree t) btSize (Leaf _) = 1 btSize (Branch left _ right) = 1 + btSize left + btSize right
So the following is a value of type BinTree Char
Branch (Leaf ’a’) ’b’ (Leaf ’c’)
SLIDE 25 3BA31 Formal Methods 49
Namespaces
In Haskell we can classify identifier tokens into two types:
- Those starting with lowercase alpha followed by alphanum:
a, b1, idWithCapSepWords, identifier with underscores.
These are used for names of functions and variables/values
- Those starting with uppercase alpha followed by alphanum:
A, B1, True, Leaf, Branch
These are used as names of Types and Type-/Data-Constructors
3BA31 Formal Methods 50
Function and Operator Fixity
In Haskell we write function/operators in two ways:
- conventional identifiers (lowercase alpha followed by alphanum:
a, b1, idWithCapSepWords, identifier with underscores.
These are prefix function names by default.
- Symbols (“funny” characters)
++, <=, :, $!$, $, =:::=.
These are infix operator names by default. Prefix function names (of arity 2) and infix operators can be converted into each other as follows: Normal Use Converted Use
f a b a ‘f‘ b a + b (+) a b
SLIDE 26 3BA31 Formal Methods 51
Type Classes in Haskell
Haskell allows us to define the notion of type classes:
- A class defines a number of functions/values over types of that class
- A type is an instance of a class if instances of those functions and values are defined for that type
- Type-classes support ad-hoc overloading — the use of a single symbol to represent a number of
different but related functions.
3BA31 Formal Methods 52
Class Example: Equality
Assume we have builtin functions defining equality for various basic types:
primitive primEqChar :: Char -> Char -> Bool primitive primEqInt :: Int -> Int -> Bool primitive primEqFloat :: Float -> Float -> Bool
We define a class Eq (equality) which requires a symbol == to be defined:
class Eq a where (==), (/=) :: a -> a -> Bool
- - Minimal complete definition: (==) or (/=)
x == y = not (x/=y) x /= y = not (x==y)
We can now define instances of == for Char, Int and Float:
instance Eq Char where (==) = primEqChar instance Eq Int where (==) = primEqInt instance Eq Float where (==) = primEqFLoat
We can now use == to denote equality between these different types.
SLIDE 27
3BA31 Formal Methods 53
More Equality
We can define class instances which depend on others. For example, given any type of class Eq (i.e. for which == is defined), we can define equality over lists of that type:
instance Eq a => Eq [a] where [] == [] = True (x:xs) == (y:ys) = x==y && xs==ys _ == _ = False
Given previous definitions, this now means == can be used with arguments of type [Char],
[Int], [Float].
Indeed we can nest such instances, so equality is now also defined for [[Char]], [[[Int]]], etc. In Haskell, == is predefined for all its builtin-types, (except for functions).
3BA31 Formal Methods 54
Class Example: Ordering
A class definition can depend on another — consider the ordering class Ord which defines <=, >=, among others. We have an ordering result type Ordering, and again some builtin comparison operators:
data Ordering = LT | EQ | GT primitive primCmpChar :: Char -> Char -> Ordering primitive primCmpInt :: Int -> Int -> Ordering primitive primCmpFloat :: Float -> Float -> Ordering
We define the class Ord as follows:
class (Eq a) => Ord a where compare :: a -> a -> Ordering (<), (<=), (>=), (>) :: a -> a -> Bool max, min :: a -> a -> a .... details omitted ....
The complete definition allows us to define everything in terms of either compare or <.
SLIDE 28 3BA31 Formal Methods 55
Class Example: Show
There is a class Show concerned with converting a value into a printable string:
class Show a where showsPrec :: Int -> a -> ShowS show :: a -> String showList :: [a] -> ShowS
- - Mimimal complete definition:
- show or showsPrec
showsPrec _ x s = show x ++ s
A value needs to be of class Show in order for Hugs to show it.
3BA31 Formal Methods 56
Deriving Instances
For certain builtin classes (Eq, Ord, Show) we can ask the compiler to automatically generate instances for out ADTs:
data BinTreeInt = LeafI Int | BranchI BinTreeInt Int BinTreeInt deriving (Eq,Ord,Show)
Haskell will define equality in the “obvious” way, and come up with an ordering where a Leaf is less than a Branch. Values of type BinTreeInt will print as we would write them in Haskell.
SLIDE 29 3BA31 Formal Methods 57
Class Example: Numbers
There are a range of classes defining different aspects of numbers. The most prevalent is Num:
class (Eq a, Show a) => Num a where (+), (-), (*) :: a -> a -> a negate :: a -> a abs, signum :: a -> a fromInteger :: Integer -> a
- - Minimal complete definition:
- All, except negate or (-)
x - y = x + negate y negate x = 0 - x
3BA31 Formal Methods 58
VDM♣ in Haskell
We can encode VDM♣ expressions (Sets, Maps, etc) in Haskell
- IVDM Haskell Module, importing:
– IVDM Set, defining (finite) sets in Haskell; – IVDM Map, defining (finite) maps in Haskell; – IVDM Rel, defining (finite) relations in Haskell. We can use Haskell to evaluate such expressions Haskell acts as an VDM♣ “Calculator”. We cannot use Haskell to prove properties, but we will be able to use it to test them (using a package called QuickCheck). The Haskell implementation makes use of the class system, in particular requiring set and map elements to belong to the Eq and Ord classes.
SLIDE 30 3BA31 Formal Methods 59
VDM♣ Types in Haskell
Let A, B and C denote VDM♣ types, and a, b and c be the corresponding Haskell types. The following VDM♣ types have the following direct counterparts in Haskell: Type VDM♣ Haskell Boolean
B Bool
Naturals
N Integer, Int (non-negative)
Integers
Z Integer, Int
Rationals
Q Float, Double
Reals
R Float, Double (finite approximations)
Characters
A Char
Sequences A
∗
[a]
Pairs A × B
(a,b)
Tuples A × · · · × C
(a,..,c)
Functions A → B
a -> b
3BA31 Formal Methods 60
Sets in Haskell
Module: IVDM Set Defines sets and operations for any Haskell instances of the Ord class. VDM♣ type PA represented by Haskell type Set a. The resulting sets are themselves instances of Ord, so we can define sets of sets, etc. Many set operators have Haskell counterparts: VDM♣ Haskell VDM♣ Haskell VDM♣ Haskell
∅ nullSet { x } iSet x ∈ mOf ∪ union ∩ intersect △ symdiff # card
sreduce (op,id) Pf smap f
SLIDE 31 3BA31 Formal Methods 61
Set Examples
Let S1, S2, . . . denote VDM♣ sets while s1, s2, . . . denote their Haskell counterparts. VDM♣ Haskell S1 ∪ S2 ∩ S3
s1 ‘union‘ s2 ‘intersect‘ s3
x ∈ S1
x ‘mOf‘ s1 ⊳ −[S1]S2 sremove s1 s2 (+/ ◦ P#)S1 (sreduce ((+),0) . smap card) s1 { 1, 3, 5 } iSet 1 ‘union‘ iSet 3 ‘union‘ iSet 5 elems [1,3,5]
Functional composition (◦) is denoted in Haskell by . [ DEMO: Sets in Haskell ]
3BA31 Formal Methods 62
Maps in Haskell
Module: IVDM Map Defines maps and operations for any Haskell instances of the Ord class. VDM♣ type A
m
→ B represented by Haskell type Map a b.
The resulting maps are themselves instances of Ord, so we can define maps of maps, etc. Many map operators have Haskell counterparts: VDM♣ Haskell VDM♣ Haskell VDM♣ Haskell
θ nullMap {x → y} iMap x y ⊔ mextend †
⊳ −[S] mremove s ⊳[S] mrestrict
dom
dom rng rng
f
m
→ g mmap f g
SLIDE 32 3BA31 Formal Methods 63
Map Examples
Let µ1, µ2, . . . denote VDM♣ maps while m1, m2, . . . denote their Haskell counterparts. VDM♣ Haskell
µ1 † µ2 ⊔ µ3 m1 ‘override‘ m2 ‘mextend‘ m3
x ∈ dom µ1
x ‘mOf‘ (dom m1) ⊳ −[S1] µ2 mremove s1 m2 (f
m
→ g) µ1 mmap f g m1 {1 → ‘a’, 5 → ‘e’} iMap 1 ’a’ ‘mextend‘ iMap 5 ’e’ mkMap [(1,’a’),(5,’e’)]
Functional composition (◦) is denoted in Haskell by . [ DEMO: Maps in Haskell ]
3BA31 Formal Methods 64
Modelling Example (1)
Consider a simple model of a spell-checking Dictionary: D ∈ Dict
= PWord
D0
:
Dict D0
∅
We can model this in Haskell as
type Wrd = String type Dict = Set Wrd d0 :: Dict d0 = nullSet
SLIDE 33 3BA31 Formal Methods 65
Modelling Example (2)
We define an operation to insert a word into the dictionary as: Ins
:
Word → Dict → Dict Ins(w)D
D ∪ { w } The Haskell version:
ins :: Wrd -> Dict -> Dict ins w d = d ‘union‘ iSet w
3BA31 Formal Methods 66
Modelling Example (3)
We can define word lookup: Lkp
:
Word → Dict → B Lkp(w)D
w ∈ D and the Haskell equivalent:
lkp :: Wrd -> Dict -> Bool lkp w d = w ‘mOf‘ d
SLIDE 34 3BA31 Formal Methods 67
Scribbles 6 : A Binary Tree
The binary tree BranchI (LeafI 1) 2 (LeafI 3) can be viewed as BranchI
2
3
Leaf Leaf