Skip to content


A record is a special data type which contain one or more data constructors, each with labeled type arguments.

For example, the following defines a record type Person with a single constructor mkPerson that takes two arguments, name and age, of types String and Nat, respectively.

  type Person :=
    mkPerson {
      name : String;
      age : Nat

In each type constructor of the record, the type arguments are called fields. Each field consists of a name and type. The field's name can be used to access to the value connected with the term of the record type.

The syntax for declaring a record type is as follows:

type <record name> <type parameters> :=
    | <type-constructor1> {
        <field1-1> : <type1-n>;
        <field1-n> : <type1-n>
    | ...
    | <type-constructor-n> {
        <fieldn-1> : <typen-1>;
        <fieldn-n> : <typen-n>

Using Records

Records are just like any other data type. They can be used in local definitions, exported from a module, and used in pattern matching.

That is, one could define a record with a single constructor or multiple constructors. For instance, here is an example declaring the newType record type declaration with the mkNewtype type constructor and one filed named f.

type T := constructT : T;

type newtype := mkNewtype {f : T};

We could also define a record with multiple constructors. For instance, let us define the record type called Pair to model pairs of values. The Pair type has a single mkPair type constructor that takes two arguments, called fst and snd, of types A and B, respectively.

type Pair (A B : Type) :=
  mkPair {
    fst : A;
    snd : B

To use this type, create a Pair type term (a pair) using the mkPair type constructor and supplying values for each field.

p1 : Pair T T :=
  mkPair (fst := constructT; snd := constructT);

Field names enable access to their associated values. For instance, another pair equivalent to the one defined above can be declared using values extracted via the field names.

p1' : Pair T T :=
  mkPair (fst := Pair.fst p1; snd := Pair.snd p1);

The fields record type's fields are qualified by the type name by default. To access the fields without the type name, use the open keyword to bring these names into scope.

open Pair;

flipP : Pair T T := mkPair (fst := snd p1; snd := fst p1);

Lastly, let us declare a record with multiple constructors.

type EnumRecord :=
  | C1 {
      c1a : T;
      c1b : T
  | C2 {
      c2a : T;
      c2b : T

p2 : Pair EnumRecord EnumRecord :=
    (fst := C1 (c1a := constructT; c1b := constructT);
    snd := C2 (c2a := constructT; c2b := constructT));