Simple Datatypes
Enumeration Types
Create simple enumerations:Z3_mk_enumeration_sort(c, name, n, enum_names, enum_consts, enum_testers) (api_datatype.cpp:88)
Tuple Types
Create product types (tuples):Z3_mk_tuple_sort(c, name, num_fields, field_names, field_sorts, mk_tuple_decl, proj_decls) (api_datatype.cpp:26)
Recursive Datatypes
List Type
Define recursive list structures:Z3_mk_list_sort(c, name, elem_sort, nil_decl, is_nil_decl, cons_decl, is_cons_decl, head_decl, tail_decl) (api_datatype.cpp:157)
Tree Type
Define binary trees:Constructor Operations
Define Constructors
Z3_mk_constructor(c, name, tester, num_fields, field_names, sorts, sort_refs) (api_datatype.cpp:220)
Recognizers (Type Tests)
Test which constructor was used:Accessors (Field Access)
Access fields of constructed values:Z3_query_constructor (api_datatype.cpp:259)
Mutually Recursive Datatypes
Define multiple datatypes that reference each other:Z3_mk_datatypes(c, num_sorts, sort_names, sorts, constructor_lists) (api_datatype.cpp:456)
Polymorphic Datatypes
Create datatypes parameterized by type variables:Z3_mk_polymorphic_datatype(c, name, num_parameters, parameters, num_constructors, constructors) (api_datatype.cpp:378)
Update Operations
Update fields of datatype values:Z3_datatype_update_field(c, f, t, v) (api_datatype.cpp:669)
Query Functions
Get information about datatypes:Z3_is_recursive_datatype_sort(c, t)(api_datatype.cpp:498)Z3_get_datatype_sort_num_constructors(c, t)(api_datatype.cpp:508)Z3_get_datatype_sort_constructor(c, t, idx)(api_datatype.cpp:543)Z3_get_datatype_sort_recognizer(c, t, idx)(api_datatype.cpp:552)Z3_get_datatype_sort_constructor_accessor(c, t, idx_c, idx_a)(api_datatype.cpp:575)
Complete Examples
Example 1: Expression Tree
Example 2: Option Type (Maybe)
Example 3: JSON-like Structure
Example 4: State Machine
Pattern Matching
Use recognizers and accessors to implement pattern matching:Theory Features
- Constructors are injective: Different arguments produce different values
- Constructors are disjoint: Values from different constructors are always distinct
- Acyclic constraint: Prevents infinite values in recursive types
- Exhaustive: Every value is constructed by exactly one constructor
Implementation Notes
- Datatypes compile to uninterpreted functions with axioms
- Recognizers enforce constructor disjointness
- Accessors are only valid after recognizer check
- Recursive types require special encoding to ensure termination
References
- Implementation:
src/api/api_datatype.cpp - Theory plugin:
src/ast/datatype_decl_plugin.h
