Unformatted text preview: Adding Effects: The fail Command Syntax:
comm ::= fail Semantics:
Must terminate program execution immediately, reporting the last state encountered.
⇒ failure is similar to nontermination:
if any executed command diverges, the whole program diverges
if any executed command fails,
the whole program fails
⇒ semantics of sequencing may use a lifting function similar to (−)⊥
⊥
but propagating failure instead of nontermination The Failure Domain
The semantic domain must be extended to account for failure:
ˆ def
Σ = Σ ∪ ({abort} × Σ)
{normal, abort} × Σ (more abstract)
Σ+Σ The meanings of commands are now of type
[[c]]comm ˆ
∈ Σ → (Σ)⊥ [[fail]]comm σ = abort, σ Semantic equations for the primitive commands remain “unchanged”:
[[v := e]]comm σ = [σ  v : [[e]]intexp σ ]
[[skip]]comm σ = σ but more abstractly they are modiﬁed to
[[v := e]]comm σ = normal, [σ  v : [[e]]intexp σ ]
[[skip]]comm σ = normal, σ Sequential Composition with Failure
Semantics of sequential composition uses another lifting:
[[c0 ; c1]]comm = ([[c1]]comm )∗ · [[c0]]comm ˆ
ˆ
ˆ
where for every f ∈ S → T⊥ the function f∗ ∈ S⊥ → T⊥ is deﬁned by
f∗ ⊥ = ⊥ f∗normal, x = f x f∗abort, x = abort, x The semantics of while was deﬁned using that of sequencing, so
def
[[while b do c]]comm = Y[Σ→Σ ]F
ˆ
⊥ where F f σ = if [[b]]boolexp σ = true then f∗([[c]]comm σ ) else normal, σ Note: These commands are semantically equivalent (for any command c)
in a language without failure, but not in one with:
c ; while true do skip while true do skip Local Declarations with Failure: Problem
Recall the semantics of local declarations
[[newvar v := e in c]]comm σ = ([−  v : σ v ])⊥ ([[c]]comm [σ  v : [[e]]intexp σ ])
⊥ The na¨ve generalization in the presence of failure
ı [[newvar v := e in c]]comm σ = ([−  v : σ v ])∗ ([[c]]comm [σ  v : [[e]]intexp σ ])
doesn’t quite work: if c fails, the result shows the state when c failed:
[[newvar x:= 1 in fail]]comm σ = abort, [σ  x : 1]
so names of local variables can be exported out of scope
⇒ renaming does not preserve meaning:
[[x:= 0 ; newvar x:= 1 in fail]]comm σ = abort, [σ  x : 1] [[x:= 0 ; newvar y:= 1 in fail]]comm σ = abort, [σ  x : 0  y : 1]
Conclusion: The old bindings of local variables must be restored
even when the result is in {abort} × Σ. Local Declarations with Failure: Solution ˆ
ˆ
Use yet another lifting function to restore bindings: if f ∈ S → T , then f† ∈ S⊥ → T⊥
f† ⊥ = ⊥ f†abort, x = abort, f x Then f†normal, x = normal, f x
[[newvar v := e in c]]comm σ = ([−  v : σ v ])† ([[c]]comm [σ  v : [[e]]intexp σ ]) Effectively failure is “caught” at local declarations
and “reraised” after the old binding is restored. Semantics of Failure
ˆ
Σ = {normal, abort} × Σ [[c]]comm ˆ
∈ Σ → (Σ)⊥ [[fail]]comm σ = abort, σ [[v := e]]comm σ = normal, [σ  v : [[e]]intexp σ ]
[[skip]]comm σ = normal, σ [[c0 ; c1]]comm σ = ([[c1]]comm )∗([[c0]]comm σ )
[[newvar v := e in c]]comm σ = ([−  v : σ v ])† ([[c]]comm [σ  v : [[e]]intexp σ ])
f∗ ⊥ = ⊥ f∗normal, σ = f σ f∗abort, σ = abort, σ f† ⊥ = ⊥ f†normal, σ = normal, f σ
f†abort, σ = abort, f σ (the equations for the conditional and the loop look unchanged) Speciﬁcations with Failure
Recall semantics of total and partial correctness:
[[[p] c [q ]]]spec = ∀σ ∈ Σ. [[p]]assert σ ⇒
([[c]]comm σ = ⊥ and [[q ]]assert ([[c]]comm σ ))
[[{p} c {q }]]spec = ∀σ ∈ Σ. [[p]]assert σ ⇒
([[c]]comm σ = ⊥ or [[q ]]assert ([[c]]comm σ ))
Our assertion language cannot handle results in {abort} × Σ,
so we treat these results as failing to satisfy an assertion:
[[[p] c [q ]]] = ∀σ ∈ Σ. [[p]]σ ⇒ ([[c]]σ ∈ {⊥} ∪ ({abort} × Σ) and [[q ]]([[c]]σ ))
/
[[{p} c {q }]] = ∀σ ∈ Σ. [[p]]σ ⇒ ([[c]]σ ∈ {⊥} ∪ ({abort} × Σ) or [[q ]]([[c]]σ ))
Then the strongest rules for fail are
(FLT) [false] fail [false]
(FLP) {true} fail {false} More Effects: Intermediate Output
Syntax: comm ::= !intexp
Intended semantics:
!e outputs the value of e (and then the execution continues).
Major change in program meaning:
Even two nonterminating programs
may have observably different behaviors.
Part of the result of executing a program is its output,
which can be an inﬁnite object. Semantics of Output: The Domain of Sequences
Example:
!0 ; while n ≥ 0 do if n = 0 then (!n ; n:= n+1) else skip
A program can behave in one of three ways:
Output a ﬁnite sequence and then terminate (normally or failing)
Output a ﬁnite sequence and then diverge without further output
Output an inﬁnite sequence
⇒ the output domain can be deﬁned (up to isomorphism) as
def Ω= ∞
n=0 (Zn ˆ
× Σ) ∪ ∞
n=0 Zn ∪ ZN Partial Order in the Domain of Sequences
The partial order should reﬂect the idea that
ω ω if output ω is “more deﬁned” than output ω .
If “more deﬁned” is interpreted with respect to the length of observation, we get
ω ω ⇐⇒ ω is a preﬁx of ω
Then the empty sequence is the least element of Ω.
There are three kinds of chains in Ω:
(diverging with ﬁnite output) 7 7, 0 7, 0 7, 0 . . . 7 7, 0 7, 0, σ 7, 0, σ . . .
ˆ
ˆ (terminating) 7 7, 0 7, 0, 7 7, 0, 7, 1 . . . Only chains of the latter kind are interesting, and their limits are in Ω since ZN ⊆ Ω:
if ω0 ω1 . . . is such a chain, then ∞
n=0 ωn = { [i, ωj i]  j ∈ N and i ∈ dom ωj } The Domain of Sequences as an Initial Continuous Algebra Idea: represent Ω = ∞
n=0 ˆ
(Zn × Σ) ∪ ∞
n=0 Zn ∪ ZN using abstract syntax. The constructors are
ι⊥ ∈ {{}} → Ω ιterm ∈ Σ → Ω ιabort ∈ Σ → Ω ιout ∈ Z × Ω → Ω (+ is concatenation of sequences)
+ ι⊥ = ιterm σ = σ ιabort σ = abort, σ ιout n, ω = n + ω
+ Finite applications of constructors deﬁne an initial algebra – the ﬁnite sequences in Ω.
Completing this set with its limits deﬁnes Ω as an initial continuous algebra. Semantics in the Domain of Sequences
The semantic equations become
[[−]]comm ∈ comm → Σ → Ω [[skip]]comm σ = ιterm σ
[[v := e]]comm σ = ιterm [σ  v : [[e]]intexp σ ] [[fail]]comm σ = ιabort σ
[[!e]]comm σ = ιout [[e]]intexp σ, ιterm σ
[[c0 ; c1]]comm σ = ([[c1]]comm )∗([[c0]]comm σ ) [[newvar v := e in c]]comm σ = ([−  v : σ v ])† ([[c]]comm [σ  v : [[e]]intexp σ ])
f∗ ⊥ = ⊥ f∗(ιterm σ ) = f σ f∗(ιabort σ ) = ιabort σ
f∗(ιout n, ω ) = ιout n, f∗ ω f† ⊥ = ⊥ f†(ιterm σ ) = ιterm (f σ )
f†(ιabort σ ) = ιabort (f σ ) f†(ιout n, ω ) = ιout n, f† ω (the equations for the conditional and the loop still look unchanged) Semantics of Output: An Example [[!3 ; !6 ; fail]] σ
=
=
=
=
=
=
=
=
= [[fail]]∗ ([[!6]]∗ ([[!3]] σ )) [[fail]]∗ ([[!6]]∗ (ιout 3, ιterm σ ))
[[fail]]∗ (ιout 3, [[!6]]∗ (ιterm σ ))
[[fail]]∗ (ιout 3, [[!6]] σ )
[[fail]]∗ (ιout 3, ιout 6,
ιout 3, [[fail]]∗ (ιout 6, ιterm σ )
ιterm σ ) ιout 3, ιout 6, [[fail]]∗ (ιterm σ )
ιout 3, ιout 6, [[fail]] σ
ιout 3, ιout 6, ιabort σ f∗ (ιout n, ω ) = ιout n, f∗ ω
f∗ (ιterm σ ) = f σ Products of Predomains
If P1, . . . , Pn are predomains, then P1 × . . . × Pn is the predomain over their Cartesian
product
{ x1, . . . , xn  x1 ∈ P1 and . . . and xn ∈ Pn }
with the induced componentwise partial order
x1, . . . , xn y1, . . . , yn ⇐⇒ x1 1 y1 and . . . and xn n yn
and limit
∞
∞
∞
1 (i)
n (i)
(i)
(i)
x1 , . . . , x n =
x1 , . . . ,
xn
i=0
i=0
i=0 If Pk are domains, then ⊥1, . . . , ⊥n is the least element of P1 × . . . × Pn.
n
Then the projections πk are continuous functions, and if fi are continuous, then so are
f1 ⊗ . . . ⊗ fn and f1 × . . . × fn. Sums of Predomains
If P1, . . . , Pn are predomains, then P1 + . . . + Pn is the predomain over their sum
{ 0, x  x ∈ P1 } ∪ . . . ∪ { n − 1, x  x ∈ Pn }
ordered by the injected partial orders of the components:
i, x j, y ⇐⇒ i = j and x i y.
All elements in a chain in P1 + . . . + Pn have the same tag, and the limit is
∞
i=0 j, xi = j, ∞
i=0 j xi P1 + . . . + Pn is a domain only if n = 1 and P1 is a domain.
The injections ιn are continuous functions, and if fi are continuous, then so are
k
f1 ⊕ . . . ⊕ fn and f1 + . . . + fn. Recursive Isomorphism for the Domain of Outputs Ω ∼
= σ . . . abort, σ
...
0, Ω 1, Ω ...
∼
Ω = (Σ + Σ + Z × Ω)⊥ ∃ φ ∈ Ω → (Σ + Σ + Z × Ω)⊥ ψ ∈ (Σ + Σ + Z × Ω) → Ω ⊥ such that ψ · φ = IΩ φ · ψ = I(Σ+Σ+Z×Ω)⊥ ιterm = ψ · ι↑ · ι0 ∈ Σ → Ω ιabort = ψ · ι↑ · ι1 ∈ Σ → Ω ιout = ψ · ι↑ · ι2 ∈ Z × Ω → Ω Intermediate Input: the Domain of Resumptions
Syntax:
comm ::= ?var Domain of program behaviors Ω ω :
ω = ⊥ ⇒ the program runs forever without output or input
ω = ιterm σ ⇒ the program terminates normally in state σ
ω = ιabort σ ⇒ the program fails in state σ
ω = ιout n, ω ⇒ the program outputs n and then has behavior ω
for g ∈ Z → Ω: ω = ιin g ⇒ if the program inputs n, it has behavior g n.
∼
Ω = (Σ + Σ + (Z × Ω) + (Z → Ω))⊥
ιin = ψ · ι↑ · ι3 ∈ (Z → Ω) → Ω Semantics of Intermediate Input
[[?v ]]comm σ = ιin (λn ∈ Z. ιterm [σ  v : n])
f∗ ⊥ = ⊥ f† ⊥ = ⊥ f∗(ιterm σ ) = f σ f∗(ιabort σ ) = ιabort σ
f∗(ιout n, ω ) = ιout n, f∗ ω f∗(ιin g ) = ιin (λn ∈ Z. f∗ (g n))
[[?x ; !x]]σ =
=
=
=
=
= f†(ιterm σ ) = ιterm (f σ )
f†(ιabort σ ) = ιabort (f σ ) f†(ιout n, ω ) = ιout n, f† ω
f†(ιin g ) = ιin (f† · g ) [[!x]]∗ ([[?x]] σ ) [[!x]]∗ (ιin (λn ∈ Z. ιterm [σ  x : n]))
ιin (λn ∈ Z. [[!x]]∗ (ιterm [σ  x : n]))
ιin (λn ∈ Z. [[!x]] [σ  x : n]) ιin (λn ∈ Z. ιout [[x]] [σ  x : n], ιterm [σ  x : n])
ιin (λn ∈ Z. ιout n, ιterm [σ  x : n]) Continuation Semantics
In an implementation of c0 ; c1,
the semantics of c1 has no bearing on the result if c0 fails to terminate
⇒ the semantics of c0 determines whether c1 will be executed or not.
But from the direct semantics of sequencing
[[c0 ; c1]] σ = [[c1]]∗ ([[c0]] σ )
it looks as if the semantics of c1 determines the result;
much machinery hidden in (−)∗ to rectify this.
The semantics of output
ω = ιout n, ω ⇒ the program outputs n and then has behavior ω
also suggests it would be easier to explain a behavior in terms of what to do next,
or its continuation behavior. Continuation Semantics cont’d
Idea: let the semantic function take an extra argument κ ∈ Σ → Ω
which describes the behavior of the rest of the program. Then
[[−]]comm ∈ comm → (Σ → Ω) → Σ → Ω
[[skip]] κ σ = κ σ
[[v := e]] κ σ = κ [σ  v : [[e]]intexp σ ] [[if b then c else c]] κ σ = if [[b]]assert σ then [[c]] κ σ else [[c]] κ σ
[[c0 ; c1]] κ σ = [[c0]] (λσ ∈ Σ. [[c1]] κ σ ) σ
= [[c0]] ([[c1]] κ) σ
i.e. [[c0 ; c1]] = [[c0]] · [[c1]]
[[while b do c]] κ = YΣ→Ω F where F κ σ = if [[b]]σ then [[c]] κ σ else κ σ
[[newvar v := e in c]] κ σ = [[c]] (λσ ∈ Σ. κ [σ  v : σ v ]) [σ  v : [[e]]σ ]
[[c]]cont κ σ = κ⊥ ([[c]]direct σ ), in particular [[c]]direct = [[c]]cont ι↑
⊥
comm
comm
comm
comm Continuation Semantics
def
Idea: let the semantic function take an extra argument κ ∈ K (where K = Σ → Ω)
which is its continuation: it describes the behavior of the rest of the program,
produces an answer in Ω when applied to an initial state in Σ.
[[−]]comm ∈ comm → (Σ → Ω) → Σ → Ω i.e. the semantics of a command maps continuations to continuations:
[[−]]comm ∈ comm → K → K [[skip]] κ = λσ ∈ Σ. κ σ
=κ
i.e. [[skip]] = IK [[v := e]] κ = λσ ∈ Σ. κ [σ  v : [[e]]intexp σ ]
[[c0 ; c1]] κ = λσ ∈ Σ. [[c0]] (λσ ∈ Σ. [[c1]] κ σ ) σ
= λσ ∈ Σ. [[c0]] ([[c1]] κ) σ = [[c0]] ([[c1]] κ)
i.e. [[c0 ; c1]] = [[c0]] · [[c1]] More Continuation Semantics [[if b then c else c]] κ = λσ ∈ Σ. if [[b]]assert σ then [[c]] κ σ else [[c]] κ σ
[[while b do c]] κ = [[if b then (c ; while b do c) else skip]] κ
= λσ ∈ Σ. if [[b]]assert σ then ([[c]] · [[while b do c]]) κ σ else κ σ
= λσ ∈ Σ. if [[b]]assert σ then [[c]] ([[while b do c]] κ) σ else κ σ
= F ([[while b do c]] κ), where
F κ = λσ ∈ Σ. if [[b]]assert σ then [[c]] κ σ else κ σ
[[while b do c]] κ = YΣ→Ω F where F κ σ = if [[b]]σ then [[c]] κ σ else κ σ
[[newvar v := e in c]] κ = λσ ∈ Σ. [[c]] (λσ ∈ Σ. κ [σ  v : σ v ]) [σ  v : [[e]]σ ] Relationship Between Direct and Continuation Semantics
The connection is that
[[c]]cont κ σ = κ⊥ ([[c]]direct σ )
⊥
comm
comm i.e. [[c]]cont κ = κ⊥ · [[c]]direct
⊥
comm
comm
which can be shown by structural induction on comm , e.g.
[[skip]]cont κ = IK κ = κ κ⊥ · [[skip]]direct = κ⊥ · IΣ = κ
⊥
⊥ [[c ; c]]cont κ = [[c]]cont ([[c]]cont κ) = [[c]]cont (κ⊥ · [[c]]direct )
⊥
= (κ⊥ · [[c]]direct )⊥ · [[c]]direct
⊥
⊥ = κ⊥ · ([[c]]direct )⊥ · [[c]]direct = κ⊥ · [[c ; c]]direct
⊥
⊥
⊥
When the “ﬁnal” (or “toplevel”) continuation is the injection ι↑ ∈ Σ → Σ⊥, then
[[c]]cont ι↑ = (ι↑)⊥ · [[c]]direct
⊥
comm
comm i.e. [[c]]direct = [[c]]cont ι↑
comm
comm Continuation Semantics of Extensions For input and output,
[[!e]] κ = λσ ∈ Σ. ιout [[e]]intexp σ, κ σ [[?v ]] κ = λσ ∈ Σ. ιin (λn ∈ Z. κ [σ  v : n]) The relationship between direct and continuation semantics is then
[[c]]cont κ σ = κ∗ ([[c]]direct σ )
comm
comm or [[c]]cont κ = κ∗ · [[c]]direct
comm
comm Failure ignores the given continuation and directly produces a result
⇒ one might expect
[[fail]] κ σ = ιterm σ
but this does not work: local variables are not reset to their original bindings. Continuation Semantics of Failure
So we have to introduce a second, abortive continuation,
which the semantics of failure invokes and of local declarations augments:
[[−]]comm ∈ comm → K → K → K [[skip]] κt κf = κt [[v := e]] κt κf = λσ ∈ Σ. κt [σ  v : [[e]]intexp σ ] [[c0 ; c1]] κt κf = [[c0]] ([[c1]] κt κf ) κf
[[if b then c else c]] κt κf = λσ ∈ Σ. if [[b]]assert σ then [[c]] κt κf σ else [[c]] κt κf σ
[[while b do c]] κt κf = YΣ→Ω F
where F κ σ = if [[b]]σ then [[c]] κ κf σ else κt σ [[newvar v := e in c]] κt κf = λσ ∈ Σ. [[c]] (λσ ∈ Σ. κt [σ  v : σ v ]) (λσ ∈ Σ. κf [σ  v : σ v ]) [σ  v : [[e]]σ ] [[!e]] κt κf = λσ ∈ Σ. ιout [[e]]intexp σ, κt σ [[?v ]] κt κf = λσ ∈ Σ. ιin (λn ∈ Z. κt [σ  v : n]) [[fail]] κt κf = κf ...
View
Full Document
 Fall '09
 Comm, σ, Newvar

Click to edit the document details