User-defined types
By using the command type
, the user can declare its own types.
Abstract types
It is possible to create new uninterpreted types. They may be parametrized by one or several type variables, or be left non-parametrized.
Syntax
<abstract_type_declaration> ::= 'type' ( <type_variable> | <type_variable_list_sep_comma> )? <type_id>
<type_variable_list_sep_comma> ::= '(' <type_variable> ( ',' <type_variable> )* ')'
Examples
(* New non-parametrized uninterpreted type *)
type person
logic Alice, Bob: person
(* New type parametrized by one type variable *)
type 'a list
logic integer_lst: int list
logic boolean_lst: bool list
logic polymorphic_lst: 'a list
(* New type parametrized by several type variables *)
type ('a, 'b, 'c) t
(* Axioms may be used to put constraints on user-defined types *)
type t
type list
logic nil: list
logic cons: t, list -> list
logic hd: list -> t
logic tl: list -> list
axiom hd_cons: forall x:t. forall l:list. hd (cons(x,l)) = x
axiom tl_cons: forall x:t. forall l:list. tl (cons(x,l)) = l
goal g:
forall x,y:t. hd(tl(cons(x, cons(y, nil)))) = y
(* Another example on constraints on user-defined types, this time using polymorphism *)
type 'a set
logic empty: 'a set
logic add: 'a, 'a set -> 'a set
logic mem: 'a, 'a set -> prop
axiom mem_empty:
forall x: 'a.
not mem(x, empty: 'a set)
axiom mem_add:
forall x, y: 'a. forall s: 'a set.
mem(x, add(y, s)) <-> (x = y or mem(x, s))
logic is1, is2: int set
logic iss: int set set
goal g:
is1 = is2 ->
(not mem(1, add(2+3, empty : int set))) and
mem (is1, add (is2, iss))
Records
One way to create new types with structure is to create records. They hold several fields, which be accessed.
Syntax
(* Declaration of records *)
<record_type_declaration> ::= 'type' ( <type_variable> | <type_variable_list_sep_comma> )? <type_id> '=' <record_type>
<type_variable_list_sep_comma> ::= '(' <type_variable> ( ';' <type_variable> )* ')'
<record_type> ::= '{' <field_def> ( ',' <field_def> )* '}'
<field_def> ::= <field_id> ':' <field_type>
(* Access *)
<record_access_expr> ::= <record_id> '.' <field_id>
(* Inline record declaration *)
<record_value> ::= '{' <field_value> ( ',' <field_value> )* '}'
<field_value> ::= <field_id> '=' <value>
Examples
type sa_family_t
type sockaddr = {
sa_len: int;
sa_family: sa_family_t;
sa_data: bitv[112]
}
logic sa: sockaddr
axiom sa_len: sa.sa_len = 8
type 'a pair = {fst : 'a ; snd : 'a}
type elt
goal g7:
forall x,y:int. {fst=x; snd=y}.
fst + 1 = 2 -> x=1
Enums and Algebraic datatypes
Algebraic datatypes (ADT) are a very powerful tool which allows Alt-Ergo to reason about generic, recursive data structures.
It is possible to create enumerations, and to use records in order to construct (mutually) recursive structures and to add additionnal structures.
Examples
When no recursion is involved, we usually talk of enumerations, or simply enums, which are the simplest examples of ADT.
Example:
type poker_suit = diamond | club | heart | spade
Records may be used in ADT to give additionnal structure.
Example:
type 'a and_infty = infty | number of { x:'a }
More complex examples involve recursion.
Example:
type nat = zero | succ of { x:nat } logic one,two,three:nat axiom a: one = succ(zero) and two = succ(one) and three = succ(two)
ADT may be parametrized.
Example:
type 'a tree = NIL | Node of { left:'a tree; val:'a; right:'a tree }
It is possible to define mutually recursive structures by using the keyword
and
.Example:
type 'a tree = Empty | Node of { val:'a; children:'a forest } and 'a forest = Nil | Cons of { head:'a tree; tail:'a forest }
ADT can be used like any type. Constructors can be called just as functions (if they are defined as records) or as constants (otherwise). Example:
type 'a tree = NIL | Node of { left:'a tree; val:'a; right:'a tree } logic t:int tree axiom a: t= Node(Node(NIL,2,Node(NIL,3,NIL)),1,NIL)
Syntax
(* Declaration of ADT *)
<algebraic_type_declaration> ::= 'type' <algebraic_type_definition> ( 'and' <algebraic_type_definition> )*
<algebraic_type_definition> ::= ( <type_variable> | <type_variable_list_sep_comma> )? <type_id> '=' <abstract_type>
<type_variable_list_sep_comma> ::= '(' <type_variable> ( ';' <type_variable> )* ')'
<abstract_type> ::= <constr> ( '|' <constr> )*
<constr> ::= <id> ( 'of' <record_type> )?
<record_type> ::= '{' <field> ( ',' <field> )* '}'
<field> ::= <field_id> ':' <field_type>
(* ADT usage *)
(* TODO *)
Values of ADT can be created through the ADT’s constructors, with the same syntax as functions.