Jean-Baptiste Tristan & K. Rustan M. Leino |
function FunctionName(x: X, y: Y): R {
expression
}
function
FunctionName
x
and y
, respectively of types X
and Y
R
expression
function F(n: int, m: int): int {
n + m
}
function G(n: int): int {
F(n + n, n * n)
}
const
const constantName: Type := expression
predicate
predicate predicateName(x: X, y: Y) {
booleanExpression
}
bool
)
int
)
real
)
char
)
bv0
, bv1
, bv2
, …, bv32
, …)
is
predicate IntPlus3IsInt(n: int) { (n + 3) is int }
predicate False() { false is bool }
predicate True() { true is bool }
predicate Conjunction(a: bool, b: bool) { (a && b) is bool }
predicate Disjunction(a: bool, b: bool) { (a || b) is bool }
predicate Implication(a: bool, b: bool) { (a ==> b) is bool }
predicate Explication(a: bool, b: bool) { (a <== b) is bool }
predicate Equivalence(a: bool, b: bool) { (a <==> b) is bool }
predicate Negation(a: bool) { !a is bool }
predicate DecimalLiteral() { 38 is int }
predicate HexadecimalLiteral() { 0xBadDecaf is int }
predicate ReadableLiteral() { 4_345_765 is int }
predicate Negation(n: int) { -n is int }
predicate Addition(n: int, m: int) { (n + m) is int }
predicate Substraction(n: int, m: int) { (n - m) is int }
predicate Multiplication(n: int, m: int) { (n * m) is int }
predicate Division(n: int, m: int) { (n / m) is int }
predicate Modulus(n: int, m: int) { (n % m) is int }
predicate Equality(n: int, m: int) { (n == m) is bool }
predicate Disequality(n: int, m: int) { (n != m) is bool }
predicate SmallerOrEqual(n: int, m: int) { (n <= m) is bool }
predicate Smaller(n: int, m: int) { (n < m) is bool }
predicate GreaterOrEqual(n: int, m: int) { (n >= m) is bool }
predicate Greater(n: int, m: int) { (n > m) is bool }
predicate DecimalLiteral() { 38.98 is real }
predicate ReadableLiteral() { 4_345_765.999_987 is real }
predicate Negation(n: real) { -n is real }
predicate Addition(n: real, m: real) { (n + m) is real }
predicate Substraction(n: real, m: real) { (n - m) is real }
predicate Multiplication(n: real, m: real) { (n * m) is real }
predicate Division(n: real, m: real) { (n / m) is real }
predicate Equality(n: real, m: real) { (n == m) is bool }
predicate Disequality(n: real, m: real) { (n != m) is bool }
predicate SmallerOrEqual(n: real, m: real) { (n <= m) is bool }
predicate Smaller(n: real, m: real) { (n < m) is bool }
predicate GreaterOrEqual(n: real, m: real) { (n >= m) is bool }
predicate Greater(n: real, m: real) { (n > m) is bool }
predicate IntegerToReal(k: int) { (k as real) is real }
predicate Floor(n: real) { (n.Floor) is int }
predicate ASCII() { 'a' is char }
predicate SingleQuote() { '\'' is char }
predicate DoubleQuote() { '\"' is char }
predicate BackSlash() { '\\' is char }
predicate NullCharacter() { '\0' is char }
predicate LineFeed() { '\n' is char }
predicate CarriageReturn() { '\r' is char }
predicate Tab() { '\t' is char }
predicate Unicode() { '\U{1F71D}' is char }
predicate Addition(a: char, b: char) { (a + b) is char }
predicate Substraction(a: char, b: char) { (a - b) is char }
predicate Less(a: char, b: char) { (a < b) is bool }
predicate LessEqual(a: char, b: char) { (a <= b) is bool }
predicate Greater(a: char, b: char) { (a > b) is bool }
predicate GreaterEqual(a: char, b: char) { (a >= b) is bool }
predicate ConditionalExpression<T>(bexpr: bool, expr1: T, expr2: T) {
(if bexpr then expr1 else expr2) is T
}
predicate LetBinding<U, V>(expr1: U, expr2: V) { (var x := expr1; expr2) is V }
predicate Tuple<T, U, V>(t: T, u: U, v: V) { (t, u, v) is (T, U, V) }
predicate TupleAccess0<T, U, V>(tup: (T, U, V)) { tup.0 is T }
predicate TupleAccess1<T, U, V>(tup: (T, U, V)) { tup.1 is U }
predicate TupleAccess2<T, U, V>(tup: (T, U, V)) { tup.2 is V }
x
is not a mutable variable
x
cannot be updated, it is just a name for the value of expr1
x
with expr1
in expr2
without changing the value of the expression
X
, Y
, Z
U
(X, Y, Z) -> U
function Apply(f: int -> int, n: int): int {
f(n)
}
function ApplyPartial(f: int -> int -> int, n: int): int -> int {
f(n)
}
function Factorial(n: int): int {
if n == 0 then 1 else n * Factorial(n - 1)
}
predicate LambdaAbstraction<U, V>(expr: V) { ((x: U) => expr) is U -> V }
predicate Application<U, V>(fun: U -> V, arg: U) { fun(arg) is V }
Small
and Large
datatype Size =
| Small
| Large
predicate Constructor() { Small is Size }
predicate Equality(a: Size, b: Size) { (a == b) is bool }
predicate Disequality(a: Size, b: Size) { (a != b) is bool }
function SizeToOunces(s: Size): int {
match s
case Small => 4
case Large => 8
}
predicate MatchExpression(s: Size) {
(match s case Small => 4 case Large => 8) is int
}
Coffee
is a constructor: it takes a value of type Size
and produces a value of type Drink
Coffee(Small)
is a value
datatype Drink =
| Coffee(Size)
| Tea(Size)
| Water(Size)
predicate Constructor() { (Tea(Small)) is Drink }
Coffee
and Tea
cannot be used without being fully applied
function GetCaffeine(d: Drink): int {
match d
case Coffee(s) => 5 * SizeToOunces(s)
case Tea(s) => 7 * SizeToOunces(s)
case Water(s) => 0
}
function GetCaffeine(d: Drink): int {
match d
case Coffee(s) => 5 * SizeToOunces(s)
case Tea(s) => 7 * SizeToOunces(s)
case Water(_) => 0
}
function GetCaffeine(d: Drink): int {
match d
case Coffee(s) => 5 * SizeToOunces(s)
case Tea(s) => 7 * SizeToOunces(s)
case _ => 0
}
datatype Drink =
| Coffee(sz: Size)
| Tea(sz: Size)
| Water(sz: Size)
predicate Discriminator(d: Drink) { d.Coffee? is bool }
predicate Destructor(d: Drink) { d.sz is Size }
function GetCaffeine(d: Drink): int {
if d.Coffee? then
5 * SizeToOunces(d.sz)
else if d.Tea? then
7 * SizeToOunces(d.sz)
else
0
}
this
datatype Size =
| Small
| Large
{
predicate This() { this is Size }
}
datatype Size =
| Small
| Large
{
function ToOunces(): int {
match this
case Small => 4
case Large => 8
}
}
predicate DotExpression(s: Size) { s.ToOunces is () -> int }
datatype Complex = Complex(r: real, i: real)
List
is a type operator: it takes a type as an argument and creates a new type
datatype List<T> =
| Nil
| Cons(head: T, tail: List)
function Len<T>(l: List<T>): nat {
match l
case Nil => 0
case Cons(_, tail) => 1 + Len(tail)
}
function Len<T>(l: List): nat {
match l
case Nil => 0
case Cons(_, tail) => 1 + Len(tail)
}
function TestEquality<T(==)>(a: T, b: T): bool {
a == b
}
seq<T>
)
set<T>
and iset<T>
)
multiset<T>
)
map<K, V>
and imap<K, V>
)
string
is a type synonym for seq<char>
predicate Empty<T>() { [] is seq<T> }
predicate SequenceDisplay<T>(x: T, y: T, z: T) { [x, y, z] is seq<T> }
predicate Equality<T(==)>(a: seq, b: seq) { (a == b) is bool }
predicate Disequality<T(==)>(a: seq, b: seq) { (a != b) is bool }
predicate ProperPrefix<T(==)>(a: seq, b: seq) { (a < b) is bool }
predicate Prefix<T(==)>(a: seq, b: seq) { (a <= b) is bool }
predicate Concatenation<T>(a: seq, b: seq) { (a + b) is seq<T> }
predicate Membership<T(==)>(a: seq, e: T) { (e in a) is bool }
predicate Absence<T(==)>(a: seq, e: T) { (e !in a) is bool }
predicate Size<T>(a: seq) { |a| is int }
predicate Indexing<T>(a: seq, k: int) { a[k] is T }
predicate Update<T>(a: seq, k: int, e: T) { a[k := e] is seq<T> }
predicate Slice<T>(a: seq, k: int, l: int) { a[k..l] is seq<T> }
predicate Drop<T>(a: seq, k: int) { a[k..] is seq<T> }
predicate Take<T>(a: seq, l: int) { a[..l] is seq<T> }
predicate Type(s: string) { s is seq<char> }
predicate Display() { "Hello" is string }
predicate EmptySet<T(==)>() { {} is set<T> }
predicate SetDisplay<T(==)>(x: T, y: T, z: T) { {x, y, z} is set<T> }
predicate Union<T(==)>(A: set<T>, B: set<T>) { (A + B) is set<T> }
predicate Intersection<T(==)>(A: set<T>, B: set<T>) { (A * B) is set<T> }
predicate AsymmetricDifference<T(==)>(A: set<T>, B: set<T>) { (A - B) is set<T> }
predicate Equality<T(==)>(A: set<T>, B: set<T>) { (A == B) is bool }
predicate Disequality<T(==)>(A: set<T>, B: set<T>) { (A != B) is bool }
predicate Subset<T(==)>(A: set<T>, B: set<T>) { (A <= B) is bool }
predicate StrictSubset<T(==)>(A: set<T>, B: set<T>) { (A < B) is bool }
predicate Superset<T(==)>(A: set<T>, B: set<T>) { (A >= B) is bool }
predicate StrictSuperset<T(==)>(A: set<T>, B: set<T>) { (A > B) is bool }
predicate Disjoint<T(==)>(A: set<T>, B: set<T>) { (A !! B) is bool }
predicate Membership<T(==)>(e: T, A: set<T>) { (e in A) is bool }
predicate Absence<T(==)>(e: T, A: set<T>) { (e !in A) is bool }
predicate Cardinality<T(==)>(A: set<T>) { |A| is int }
predicate EmptyMultiset<T(==)>() { multiset{} is multiset<T> }
predicate MultisetDisplay<T(==)>(x: T, y: T, z: T) { multiset{x, y, z} is multiset<T> }
predicate Union<T(==)>(A: multiset<T>, B: multiset<T>) { (A + B) is multiset<T> }
predicate Intersection<T(==)>(A: multiset<T>, B: multiset<T>) { (A * B) is multiset<T> }
predicate Difference<T(==)>(A: multiset<T>, B: multiset<T>) { (A - B) is multiset<T> }
predicate Equality<T(==)>(A: multiset<T>, B: multiset<T>) { (A == B) is bool }
predicate Disequality<T(==)>(A: multiset<T>, B: multiset<T>) { (A != B) is bool }
predicate Submultiset<T(==)>(A: multiset<T>, B: multiset<T>) { (A <= B) is bool }
predicate StrictSubmultiset<T(==)>(A: multiset<T>, B: multiset<T>) { (A < B) is bool }
predicate Supermultiset<T(==)>(A: multiset<T>, B: multiset<T>) { (A >= B) is bool }
predicate StrictSupermultiset<T(==)>(A: multiset<T>, B: multiset<T>) { (A > B) is bool }
predicate Disjoint<T(==)>(A: multiset<T>, B: multiset<T>) { (A !! B) is bool }
predicate Membership<T(==)>(e: T, A: multiset<T>) { (e in A) is bool }
predicate Absence<T(==)>(e: T, A: multiset<T>) { (e !in A) is bool }
predicate Cardinality<T(==)>(A: multiset<T>) { |A| is int }
predicate Multiplicity<T(==)>(e: T, A: multiset<T>) { A[e] is int }
predicate MultiplicityUpdate<T(==)>(e: T, A: multiset<T>, k: int) { A[e := k] is multiset<T> }
predicate Empty<U(==), V>() { map[] is map<U, V> }
predicate Display() { map[20 := true, 3 := false, 20 := false] is map<int,bool>}
predicate KeyMembership<U(==), V>(m: map, k: U) { (k in m) is bool }
predicate KeyAbsence<U(==), V>(m: map, k: U) { (k !in m) is bool }
predicate Cardinality<U(==), V>(m: map) { |m| is int }
predicate Indexing<U(==), V>(m: map, k: U) { m[k] is V}
predicate Update<U(==), V>(m: map, k: U, v: V) { m[k := v] is map}
predicate Keys<U(==), V>(m: map) { m.Keys is set<U> }
predicate Values<U(==), V(==)>(m: map) { m.Values is set<V> }
predicate Items<U(==), V(==)>(m: map) { m.Items is set<(U, V)> }
predicate Merge<U(==), V>(m1: map, m2: map) { (m1 + m2) is map }
predicate MapDomainSubtraction<U(==), V>(m: map, s: set) { (m - s) is map }
type Complex = (real, real)