Skip to content

Commit d162fd8

Browse files
committed
Organize lectures a bit better
1 parent b0813bf commit d162fd8

File tree

4 files changed

+109
-104
lines changed

4 files changed

+109
-104
lines changed

src/syntax1.dfy renamed to src/lec1_logic.dfy

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ function IsLarge(x: int): bool {
5050
x > 1000
5151
}
5252

53-
// New syntax (predicate): `predicate` is a shorthand for a function that returns a boolean.
54-
// Functions that return a boolean are extremely common in verification since
55-
// they express logical predicates, hence the special syntax.
53+
// New feature (predicate): `predicate` is a shorthand for a function that
54+
// returns a boolean. Functions that return a boolean are extremely common in
55+
// verification since they express logical predicates, hence the special syntax.
5656
predicate IsSmall(x: int) {
5757
!IsLarge(x)
5858
}
@@ -140,7 +140,7 @@ lemma ForallAssertionExamples()
140140
lemma AbsLargerForAll()
141141
ensures forall x: int :: abs(x) >= x
142142
{
143-
// New syntax (forall statement): a _forall statement_ allows us to help Dafny with a proof of
143+
// New feature (forall statement): a _forall statement_ allows us to help Dafny with a proof of
144144
// `forall x :: ...` by talking about an individual `x` */
145145
forall x: int
146146
ensures abs(x) >= x

src/lec2_sequences.dfy

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* More interesting data to reason about: sequences. */
2+
3+
/* In order to write proofs about interesting systems and protocols, we first
4+
need some way of modeling the state of those systems and protocols. We'll
5+
explore Dafy's built-in sequence type as well as algebraic data types, its core
6+
way of creating user-defined types. */
7+
8+
/*** Sequences ***/
9+
10+
/* These data types are very similar to data structures, but will be purely
11+
* mathematical. We'll start with the sequence type `seq<T>`. The `T` in angle
12+
* brackets is a _type parameter_, needed because sequences can hold values of
13+
* any type. A sequence is related to data structures you're familiar with like
14+
* linked lists or arrays/vectors (the terminology depends on the programming
15+
* language). A sequence is the mathematical essence of the state of a
16+
* list/vector/array without the implementation details.
17+
*/
18+
19+
lemma SequenceOperations()
20+
{
21+
// var is a (mutable) local variable, defined within a lemma
22+
var s: seq<int> := [3, 1, 2];
23+
// sequences can be indexed, starting at 1
24+
assert s[1] == 1;
25+
// we can extract a subsequence
26+
assert s[1..2] == [1];
27+
// we can re-assign the sequence and update one element using the `s[i := v]` syntax.
28+
s := s[2 := 3];
29+
assert s[0] == s[2] == 3;
30+
// `|s|` is the sequence's length
31+
assert |s| == 3;
32+
// we can append two sequences
33+
s := s + [7, 12];
34+
assert |s| == 5;
35+
assert s == [3, 1, 3, 7, 12];
36+
}
37+
38+
/* Below we give some lemmas illustrating sequence operations. */
39+
40+
function SeqGet(s: seq<int>, i: nat): int
41+
// New feature (function preconditions): functions can have _requires_
42+
// clauses, also called _preconditions_. Dafny will statically check that the
43+
// preconditions hold (in the same way as assertions) wherever a call to the
44+
// function appears.
45+
//
46+
// This particular precondition requires that the index is in-bounds. The fact
47+
// that `i` is of type `nat` already assures that it is non-negative.
48+
requires i < |s|
49+
{
50+
s[i]
51+
}
52+
53+
function SeqUpdate(s: seq<int>, i: nat, n: int): seq<int>
54+
requires i < |s|
55+
{
56+
s[i := n]
57+
}
58+
59+
lemma CheckedPreconditions(s: seq<int>, i: nat)
60+
// Dafny does not allow even stating this because it tries to index a //
61+
// sequence without a proof that the index is in-bounds, one of the preconditions
62+
// for sequence indexing.
63+
//
64+
// We'd get the same error in an ensures clause or function definition.
65+
requires s[i] > 0 // error: index out of range
66+
{}
67+
68+
lemma CheckedFunctionPreconditions(s: seq<int>, i: nat)
69+
// almost same as above, but notice that the error specifically points to the
70+
// `SeqGet` precondition
71+
requires SeqGet(s, i) > 0 // error: function precondition might not hold
72+
{}
73+
74+
lemma SequenceAppendFact(s1: seq<int>, s2: seq<int>)
75+
// New feature (forall where clause): notice the new pipe symbol after the `i`.
76+
// The general syntax is of the form `forall x | p(x) :: q(x)`; it means the
77+
// same thing as `forall x :: p(x) ==> q(x)` but can be easier to read. You
78+
// might read this as "for all x where p(x), q(x)".
79+
//
80+
// We're also leaving off the type of `i` because Dafny can infer that it's an `int`.
81+
ensures forall i | |s1| <= i < |s1| + |s2| :: (s1 + s2)[i] == s2[i - |s1|]
82+
{
83+
// goes through without any extra proof
84+
}

src/syntax2.dfy renamed to src/lec3_algebraic_datatypes.dfy

Lines changed: 19 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,16 @@
1-
/* More interesting data to reason about: sequences. */
2-
3-
/* Outline:
4-
- sequences
5-
- algebraic data types (user-defined data)
6-
*/
7-
8-
/* In order to write proofs about interesting systems and protocols, we first
9-
need some way of modeling the state of those systems and protocols. We'll
10-
explore Dafy's built-in sequence type as well as algebraic data types, its core
11-
way of creating user-defined types. */
12-
13-
/*** Sequences ***/
14-
15-
/* These data types are very similar to data structures, but will be purely
16-
* mathematical. We'll start with the sequence type `seq<T>`. The `T` in angle
17-
* brackets is a _type parameter_, needed because sequences can hold values of
18-
* any type. A sequence is related to data structures you're familiar with like
19-
* linked lists or arrays/vectors (the terminology depends on the programming
20-
* language). A sequence is the mathematical essence of the state of a
21-
* list/vector/array without the implementation details.
22-
*/
23-
24-
lemma SequenceOperations()
25-
{
26-
// var is a (mutable) local variable, defined within a lemma
27-
var s: seq<int> := [3, 1, 2];
28-
// sequences can be indexed, starting at 1
29-
assert s[1] == 1;
30-
// we can extract a subsequence
31-
assert s[1..2] == [1];
32-
// we can re-assign the sequence and update one element using the `s[i := v]` syntax.
33-
s := s[2 := 3];
34-
assert s[0] == s[2] == 3;
35-
// `|s|` is the sequence's length
36-
assert |s| == 3;
37-
// we can append two sequences
38-
s := s + [7, 12];
39-
assert |s| == 5;
40-
assert s == [3, 1, 3, 7, 12];
41-
}
42-
43-
/* Below we give some lemmas illustrating sequence operations. */
44-
45-
function SeqGet(s: seq<int>, i: nat): int
46-
// New feature (function preconditions): functions can have _requires_
47-
// clauses, also called _preconditions_. Dafny will statically check that the
48-
// preconditions hold (in the same way as assertions) wherever a call to the
49-
// function appears.
50-
//
51-
// This particular precondition requires that the index is in-bounds. The fact
52-
// that `i` is of type `nat` already assures that it is non-negative.
53-
requires i < |s|
54-
{
55-
s[i]
56-
}
57-
58-
function SeqUpdate(s: seq<int>, i: nat, n: int): seq<int>
59-
requires i < |s|
60-
{
61-
s[i := n]
62-
}
63-
64-
lemma CheckedPreconditions(s: seq<int>, i: nat)
65-
// Dafny does not allow even stating this because it tries to index a //
66-
// sequence without a proof that the index is in-bounds, one of the preconditions
67-
// for sequence indexing.
68-
//
69-
// We'd get the same error in an ensures clause or function definition.
70-
requires s[i] > 0 // error: index out of range
71-
{}
72-
73-
lemma CheckedFunctionPreconditions(s: seq<int>, i: nat)
74-
// almost same as above, but notice that the error specifically points to the
75-
// `SeqGet` precondition
76-
requires SeqGet(s, i) > 0 // error: function precondition might not hold
77-
{}
78-
79-
lemma SequenceAppendFact(s1: seq<int>, s2: seq<int>)
80-
// New syntax (forall where clause): notice the new pipe symbol after the `i`.
81-
// The general syntax is of the form `forall x | p(x) :: q(x)`; it means the
82-
// same thing as `forall x :: p(x) ==> q(x)` but can be easier to read. You
83-
// might read this as "for all x where p(x), q(x)".
84-
//
85-
// We're also leaving off the type of `i` because Dafny can infer that it's an `int`.
86-
ensures forall i | |s1| <= i < |s1| + |s2| :: (s1 + s2)[i] == s2[i - |s1|]
87-
{
88-
// goes through without any extra proof
89-
}
90-
1+
/* More interesting data to reason about: algebraic data types. */
912

923
/*** Algebraic data types ***/
934

945
/* Sequences are powerful and all, but eventually you'll want to define new data
95-
types. For that Dafny has algebraic data types which capture "products"
96-
(struct-like types) and "sums" (tagged unions). While we're explaining algebraic
97-
data types we'll take a short break from lemmas/proofs and just explain this bit
98-
of functional programming. */
6+
* types. For that Dafny has algebraic data types which capture "products"
7+
* (struct-like types) and "sums" (tagged unions). These are often abbreviated to
8+
* "ADTs" (not to be confused with "abstract data types" which are a totally
9+
* different concept related to object-oriented programming; we won't generally
10+
* use that term). Algebraic data types are also used for programming (as opposed
11+
* to in the course where we'll only see them used for mathematical models), so
12+
* we'll take a short break and first explain them in the context of functions
13+
* before seeing them used in lemmas and assertions. */
9914

10015
/* Let's start with a struct that has two fields, x and y: */
10116
datatype Point = PointCtor(x: int, y: int)
@@ -174,19 +89,25 @@ datatype CoffeeRecipe =
17489
// a very incomplete list :)
17590

17691
// How much milk will be in my coffee drink?
92+
//
93+
// (If you don't know much about coffee, that's okay! Take this as a
94+
// specification for what these drinks are, at least as far as milk is
95+
// concerned.)
17796
function MilkOz(coffee: CoffeeRecipe): nat {
17897
match coffee {
179-
// New feature: we can put an underscore for fields that aren't needed in
180-
// some "match arm". We can also name a field and refer to it on the right side
181-
// (notice that this name also doesn't have to match the name in the datatype).
98+
// New feature (ignore patterns): we can put an underscore for fields that
99+
// aren't needed in some "match arm". We can also name a field and refer to
100+
// it on the right side (notice that this name also doesn't have to match
101+
// the name in the datatype).
182102
case Drip(_, milk) => if milk then 1 else 0
183103
case Espresso(_) => 0
184104
// standard-sized latte
185105
case Latte(_) => 8
186106
}
187107
}
188108

189-
/* Below we illustrate some reasoning about data types. */
109+
/* Now that we've seen algebraic datatypes in functions, let's start using them
110+
* in lemmas and assertions. */
190111

191112
lemma VariantsDiffer() {
192113
assert Cytosine != Guanine;

src/syntax3.dfy renamed to src/lec4_advanced.dfy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/* Outline:
44
- Opacity and revealing
55
- Recursive functions and lemmas
6-
- assign-such-that
6+
- Assign-such-that
77
*/
88

99

@@ -158,7 +158,7 @@ lemma PreviousFromC(s: State, s': State)
158158
requires Next(s, s') && s' == C
159159
ensures s == B || s == C
160160
{
161-
// New syntax (assign such that): we can assign a variable using the syntax
161+
// New feature (assign such that): we can assign a variable using the syntax
162162
// `var x:T :| p(x)` to get a (non-deterministic) value of type `T` that
163163
// satisfies `p(x)`. Dafny will first check that at least one such value
164164
// exists. As usual for `var` declarations the type `T` is optional if it can

0 commit comments

Comments
 (0)