Built-ins

The Agda type checker knows about, and has special treatment for, a number of different concepts. The most prominent is natural numbers, which has a special representation as Haskell integers and support for fast arithmetic. The surface syntax of these concepts are not fixed, however, so in order to use the special treatment of natural numbers (say) you define an appropriate data type and then bind that type to the natural number concept using a BUILTIN pragma.

Some built-in types support primitive functions that have no corresponding Agda definition. These functions are declared using the primitive keyword by giving their type signature.

Using the built-in types

While it is possible to define your own versions of the built-in types and bind them using BUILTIN pragmas, it is recommended to use the definitions in the Agda.Builtin modules. These modules are installed when you install Agda and so are always available. For instance, built-in natural numbers are defined in Agda.Builtin.Nat. The standard library and the agda-prelude reexport the definitions from these modules.

The unit type

  1. module Agda.Builtin.Unit

The unit type is bound to the built-in UNIT as follows:

  1. record : Set where
  2. {-# BUILTIN UNIT #-}

Agda needs to know about the unit type since some of the primitive operations in the reflected type checking monad return values in the unit type.

The Σ-type

  1. module Agda.Builtin.Sigma

The built-in Σ-type of dependent pairs is defined as follows:

  1. record Σ {a b} (A : Set a) (B : A Set b) : Set (a b) where
  2. constructor _,_
  3. field
  4. fst : A
  5. snd : B fst
  6. open Σ public
  7. infixr 4 _,_
  8. {-# BUILTIN SIGMA Σ #-}

Lists

  1. module Agda.Builtin.List

Built-in lists are bound using the LIST built-in:

  1. data List {a} (A : Set a) : Set a where
  2. [] : List A
  3. __ : (x : A) (xs : List A) List A
  4. {-# BUILTIN LIST List #-}
  5. infixr 5 __

The constructors are bound automatically when binding the type. Lists are not required to be level polymorphic; List : Set → Set is also accepted.

As with booleans, the effect of binding the LIST built-in is to let you use primitive functions working with lists, such as primStringToList and primStringFromList, and letting the GHC backend know to compile the List type to Haskell lists.

Maybe

  1. module Agda.Builtin.Maybe

Built-in maybe type is bound using the MAYBE built-in:

  1. data Maybe {a} (A : Set a) : Set a where
  2. nothing : Maybe A
  3. just : A Maybe A
  4. {-# BUILTIN MAYBE Maybe #-}

The constructors are bound automatically when binding the type. Maybe is not required to be level polymorphic; Maybe : Set → Set is also accepted.

As with list, the effect of binding the MAYBE built-in is to let you use primitive functions working with maybes, such as primStringUncons that returns the head and tail of a string (if it is non empty), and letting the GHC backend know to compile the Maybe type to Haskell maybes.

Booleans

  1. module Agda.Builtin.Bool where

Built-in booleans are bound using the BOOL, TRUE and FALSE built-ins:

  1. data Bool : Set where
  2. false true : Bool
  3. {-# BUILTIN BOOL Bool #-}
  4. {-# BUILTIN TRUE true #-}
  5. {-# BUILTIN FALSE false #-}

Note that unlike for natural numbers, you need to bind the constructors separately. The reason for this is that Agda cannot tell which constructor should correspond to true and which to false, since you are free to name them whatever you like.

The effect of binding the boolean type is that you can then use primitive functions returning booleans, such as built-in NATEQUALS, and letting the GHC backend know to compile the type to Haskell Bool.

Natural numbers

  1. module Agda.Builtin.Nat

Built-in natural numbers are bound using the NATURAL built-in as follows:

  1. data Nat : Set where
  2. zero : Nat
  3. suc : Nat Nat
  4. {-# BUILTIN NATURAL Nat #-}

The names of the data type and the constructors can be chosen freely, but the shape of the datatype needs to match the one given above (modulo the order of the constructors). Note that the constructors need not be bound explicitly.

Binding the built-in natural numbers as above has the following effects:

  • The use of natural number literals is enabled. By default the type of a natural number literal will be Nat, but it can be overloaded to include other types as well.

  • Closed natural numbers are represented as Haskell integers at compile-time.

  • The compiler backends compile natural numbers to the appropriate number type in the target language.

  • Enabled binding the built-in natural number functions described below.

Functions on natural numbers

There are a number of built-in functions on natural numbers. These are special in that they have both an Agda definition and a primitive implementation. The primitive implementation is used to evaluate applications to closed terms, and the Agda definition is used otherwise. This lets you prove things about the functions while still enjoying good performance of compile-time evaluation. The built-in functions are the following:

  1. _+_ : Nat Nat Nat
  2. zero + m = m
  3. suc n + m = suc (n + m)
  4. {-# BUILTIN NATPLUS _+_ #-}
  5. _-_ : Nat Nat Nat
  6. n - zero = n
  7. zero - suc m = zero
  8. suc n - suc m = n - m
  9. {-# BUILTIN NATMINUS _-_ #-}
  10. _*_ : Nat Nat Nat
  11. zero * m = zero
  12. suc n * m = (n * m) + m
  13. {-# BUILTIN NATTIMES _*_ #-}
  14. _==_ : Nat Nat Bool
  15. zero == zero = true
  16. suc n == suc m = n == m
  17. _ == _ = false
  18. {-# BUILTIN NATEQUALS _==_ #-}
  19. _<_ : Nat Nat Bool
  20. _ < zero = false
  21. zero < suc _ = true
  22. suc n < suc m = n < m
  23. {-# BUILTIN NATLESS _<_ #-}
  24. div-helper : Nat Nat Nat Nat Nat
  25. div-helper k m zero j = k
  26. div-helper k m (suc n) zero = div-helper (suc k) m n m
  27. div-helper k m (suc n) (suc j) = div-helper k m n j
  28. {-# BUILTIN NATDIVSUCAUX div-helper #-}
  29. mod-helper : Nat Nat Nat Nat Nat
  30. mod-helper k m zero j = k
  31. mod-helper k m (suc n) zero = mod-helper 0 m n m
  32. mod-helper k m (suc n) (suc j) = mod-helper (suc k) m n j
  33. {-# BUILTIN NATMODSUCAUX mod-helper #-}

The Agda definitions are checked to make sure that they really define the corresponding built-in function. The definitions are not required to be exactly those given above, for instance, addition and multiplication can be defined by recursion on either argument, and you can swap the arguments to the addition in the recursive case of multiplication.

The NATDIVSUCAUX and NATMODSUCAUX are built-ins bind helper functions for defining natural number division and modulo operations, and satisfy the properties

  1. div n (suc m) div-helper 0 m n m
  2. mod n (suc m) mod-helper 0 m n m

Machine words

  1. module Agda.Builtin.Word
  2. module Agda.Builtin.Word.Properties

Agda supports built-in 64-bit machine words, bound with the WORD64 built-in:

  1. postulate Word64 : Set
  2. {-# BUILTIN WORD64 Word64 #-}

Machine words can be converted to and from natural numbers using the following primitives:

  1. primitive
  2. primWord64ToNat : Word64 Nat
  3. primWord64FromNat : Nat Word64

Converting to a natural number is the trivial embedding, and converting from a natural number gives you the remainder modulo 2^{64}. The proof of the former theorem:

  1. primitive
  2. primWord64ToNatInjective : a b primWord64ToNat a primWord64ToNat b a b

is in the Properties module. The proof of the latter theorem is not primitive, but can be defined in a library using primTrustMe.

Basic arithmetic operations can be defined on Word64 by converting to natural numbers, performing the corresponding operation, and then converting back. The compiler will optimise these to use 64-bit arithmetic. For instance:

  1. addWord : Word64 Word64 Word64
  2. addWord a b = primWord64FromNat (primWord64ToNat a + primWord64ToNat b)
  3. subWord : Word64 Word64 Word64
  4. subWord a b = primWord64FromNat ((primWord64ToNat a + 18446744073709551616) - primWord64ToNat b)

These compile to primitive addition and subtraction on 64-bit words, which in the GHC backend map to operations on Haskell 64-bit words (Data.Word.Word64).

Integers

  1. module Agda.Builtin.Int

Built-in integers are bound with the INTEGER built-in to a data type with two constructors: one for positive and one for negative numbers. The built-ins for the constructors are INTEGERPOS and INTEGERNEGSUC.

  1. data Int : Set where
  2. pos : Nat Int
  3. negsuc : Nat Int
  4. {-# BUILTIN INTEGER Int #-}
  5. {-# BUILTIN INTEGERPOS pos #-}
  6. {-# BUILTIN INTEGERNEGSUC negsuc #-}

Here negsuc n represents the integer -n - 1. Unlike for natural numbers, there is no special representation of integers at compile-time since the overhead of using the data type compared to Haskell integers is not that big.

Built-in integers support the following primitive operation (given a suitable binding for String):

  1. primitive
  2. primShowInteger : Int String

Floats

  1. module Agda.Builtin.Float
  2. module Agda.Builtin.Float.Properties

Floating point numbers are bound with the FLOAT built-in:

  1. postulate Float : Set
  2. {-# BUILTIN FLOAT Float #-}

This lets you use floating point literals. Floats are represented by the type checker as IEEE 754 binary64 double precision floats, with the restriction that there is exactly one NaN value. The following primitive functions are available (with suitable bindings for Nat, Bool, String, Int, Maybe_):

  1. primitive
  2. -- Relations
  3. primFloatIsInfinite : Float Bool
  4. primFloatIsNaN : Float Bool
  5. primFloatIsNegativeZero : Float Bool
  6. -- Conversions
  7. primNatToFloat : Nat Float
  8. primIntToFloat : Int Float
  9. primFloatToRatio : Float Int λ _ Int)
  10. primRatioToFloat : Int Int Float
  11. primShowFloat : Float String
  12. -- Operations
  13. primFloatPlus : Float Float Float
  14. primFloatMinus : Float Float Float
  15. primFloatTimes : Float Float Float
  16. primFloatDiv : Float Float Float
  17. primFloatPow : Float Float Float
  18. primFloatNegate : Float Float
  19. primFloatSqrt : Float Float
  20. primFloatExp : Float Float
  21. primFloatLog : Float Float
  22. primFloatSin : Float Float
  23. primFloatCos : Float Float
  24. primFloatTan : Float Float
  25. primFloatASin : Float Float
  26. primFloatACos : Float Float
  27. primFloatATan : Float Float
  28. primFloatATan2 : Float Float Float
  29. primFloatSinh : Float Float
  30. primFloatCosh : Float Float
  31. primFloatTanh : Float Float
  32. primFloatASinh : Float Float
  33. primFloatACosh : Float Float
  34. primFloatATanh : Float Float

The primitive binary relations implement their IEEE 754 equivalents, which means that primFloatEquality is not reflexive, and primFloatInequality and primFloatLess are not total. (Specifically, NaN is not related to anything, including itself.)

The primFloatIsSafeInteger function determines whether the value is a number that is a safe integer, i.e., is within the range where the arithmetic operations do not lose precision.

Floating point numbers can be converted to their raw representation using the primitive:

  1. primitive
  2. primFloatToWord64 : Float Maybe Word64

which returns nothing for NaN and satisfies:

  1. primFloatToWord64Injective : a b primFloatToWord64 a primFloatToWord64 b a b

in the Properties module. These primitives can be used to define a safe decidable propositional equality with the --safe option. The function primFloatToWord64 cannot be guaranteed to be consistent across backends, therefore relying on the specific result may result in inconsistencies.

The rounding operations (primFloatRound, primFloatFloor, and primFloatCeiling) return a value of type Maybe Int, and return nothing when applied to NaN or the infinities:

  1. primitive
  2. primFloatRound : Float Maybe Int
  3. primFloatFloor : Float Maybe Int
  4. primFloatCeiling : Float Maybe Int

The primFloatDecode function decodes a floating-point number to its mantissa and exponent, normalised such that the mantissa is the smallest possible integer. It fails when applied to NaN or the infinities, returning nothing. The primFloatEncode function encodes a pair of a mantissa and exponent to a floating-point number. It fails when the resulting number cannot be represented as a float. Note that primFloatEncode may result in a loss of precision.

primitive

primFloatDecode : Float → Maybe (Σ Int λ _ → Int) primFloatEncode : Int → Int → Maybe Float

Characters

  1. module Agda.Builtin.Char
  2. module Agda.Builtin.Char.Properties

The character type is bound with the CHARACTER built-in:

  1. postulate Char : Set
  2. {-# BUILTIN CHAR Char #-}

Binding the character type lets you use character literals. The following primitive functions are available on characters (given suitable bindings for Bool, Nat and String):

  1. primitive
  2. primIsLower : Char Bool
  3. primIsDigit : Char Bool
  4. primIsAlpha : Char Bool
  5. primIsSpace : Char Bool
  6. primIsAscii : Char Bool
  7. primIsLatin1 : Char Bool
  8. primIsPrint : Char Bool
  9. primIsHexDigit : Char Bool
  10. primToUpper : Char Char
  11. primToLower : Char Char
  12. primCharToNat : Char Nat
  13. primNatToChar : Nat Char
  14. primShowChar : Char String

These functions are implemented by the corresponding Haskell functions from Data.Char (ord and chr for primCharToNat and primNatToChar). To make primNatToChar total chr is applied to the natural number modulo 0x110000. Furthermore, to match the behaviour of strings, surrogate code points are mapped to the replacement character U+FFFD.

Converting to a natural number is the obvious embedding, and its proof:

  1. primitive
  2. primCharToNatInjective : a b primCharToNat a primCharToNat b a b

can be found in the Properties module.

Strings

  1. module Agda.Builtin.String
  2. module Agda.Builtin.String.Properties

The string type is bound with the STRING built-in:

  1. postulate String : Set
  2. {-# BUILTIN STRING String #-}

Binding the string type lets you use string literals. The following primitive functions are available on strings (given suitable bindings for Bool, Char and List):

  1. primitive
  2. primStringUncons : String Maybe Char _ String))
  3. primStringToList : String List Char
  4. primStringFromList : List Char String
  5. primStringAppend : String String String
  6. primStringEquality : String String Bool
  7. primShowString : String String

String literals can be overloaded.

Converting to and from a list is injective, and their proofs:

  1. primitive
  2. primStringToListInjective : a b primStringToList a primStringToList b a b
  3. primStringFromListInjective : a b primStringFromList a primStringFromList b a b

can found in the Properties module.

Strings cannot represent unicode surrogate code points (characters in the range U+D800 to U+DFFF). These are replaced by the unicode replacement character U+FFFD if they appear in string literals.

Equality

  1. module Agda.Builtin.Equality

The identity type can be bound to the built-in EQUALITY as follows

  1. infix 4 __
  2. data __ {a} {A : Set a} (x : A) : A Set a where
  3. refl : x x
  4. {-# BUILTIN EQUALITY __ #-}

This lets you use proofs of type lhs ≡ rhs in the rewrite construction.

Other variants of the identity type are also accepted as built-in:

  1. data __ {A : Set} : (x y : A) Set where
  2. refl : (x : A) x x

The type of primEraseEquality has to match the flavor of identity type.

  1. module Agda.Builtin.Equality.Erase

Binding the built-in equality type also enables the primEraseEquality primitive:

  1. primitive
  2. primEraseEquality : {a} {A : Set a} {x y : A} x y x y

The function takes a proof of an equality between two values x and y and stays stuck on it until x and y actually become definitionally equal. Whenever that is the case, primEraseEquality e reduces to refl.

One use of primEraseEquality is to replace an equality proof computed using an expensive function (e.g. a proof by reflection) by one which is trivially refl on the diagonal.

primTrustMe

  1. module Agda.Builtin.TrustMe

From the primEraseEquality primitive, we can derive a notion of primTrustMe:

  1. primTrustMe : {a} {A : Set a} {x y : A} x y
  2. primTrustMe {x = x} {y} = primEraseEquality unsafePrimTrustMe
  3. where postulate unsafePrimTrustMe : x y

As can be seen from the type, primTrustMe must be used with the utmost care to avoid inconsistencies. What makes it different from a postulate is that if x and y are actually definitionally equal, primTrustMe reduces to refl. One use of primTrustMe is to lift the primitive boolean equality on built-in types like String to something that returns a proof object:

  1. eqString : (a b : String) Maybe (a b)
  2. eqString a b = if primStringEquality a b
  3. then just primTrustMe
  4. else nothing

With this definition eqString "foo" "foo" computes to just refl.

Sorts

The primitive sorts used in Agda’s type system (Set, Prop, and Setω) are declared using BUILTIN pragmas in the Agda.Primitive module. These pragmas should not be used directly in other modules, but it is possible to rename these builtin sorts when importing Agda.Primitive.

  1. {-# BUILTIN TYPE Set #-}
  2. {-# BUILTIN PROP Prop #-}
  3. {-# BUILTIN SETOMEGA Setω #-}

The primitive sorts Set and Prop are automatically imported at the top of every top-level Agda module, unless the --no-import-sorts flag is enabled.

Universe levels

  1. module Agda.Primitive

Universe levels are also declared using BUILTIN pragmas. In contrast to the Agda.Builtin modules, the Agda.Primitive module is auto-imported and thus it is not possible to change the level built-ins. For reference these are the bindings:

  1. postulate
  2. Level : Set
  3. lzero : Level
  4. lsuc : Level Level
  5. __ : Level Level Level
  6. {-# BUILTIN LEVEL Level #-}
  7. {-# BUILTIN LEVELZERO lzero #-}
  8. {-# BUILTIN LEVELSUC lsuc #-}
  9. {-# BUILTIN LEVELMAX __ #-}

Sized types

  1. module Agda.Builtin.Size

The built-ins for sized types are different from other built-ins in that the names are defined by the BUILTIN pragma. Hence, to bind the size primitives it is enough to write:

  1. {-# BUILTIN SIZEUNIV SizeUniv #-} -- SizeUniv : SizeUniv
  2. {-# BUILTIN SIZE Size #-} -- Size : SizeUniv
  3. {-# BUILTIN SIZELT Size<_ #-} -- Size<_ : ..Size → SizeUniv
  4. {-# BUILTIN SIZESUC _ #-} -- ↑_ : Size → Size
  5. {-# BUILTIN SIZEINF #-} -- ∞ : Size
  6. {-# BUILTIN SIZEMAX _⊔ˢ_ #-} -- _⊔ˢ_ : Size → Size → Size

Coinduction

  1. module Agda.Builtin.Coinduction

The following built-ins are used for coinductive definitions:

  1. postulate
  2. : {a} (A : Set a) Set a
  3. _ : {a} {A : Set a} A A
  4. : {a} {A : Set a} A A
  5. {-# BUILTIN INFINITY #-}
  6. {-# BUILTIN SHARP _ #-}
  7. {-# BUILTIN FLAT #-}

See Coinduction for more information.

IO

  1. module Agda.Builtin.IO

The sole purpose of binding the built-in IO type is to let Agda check that the main function has the right type (see Compilers).

  1. postulate IO : Set Set
  2. {-# BUILTIN IO IO #-}

Literal overloading

  1. module Agda.Builtin.FromNat
  2. module Agda.Builtin.FromNeg
  3. module Agda.Builtin.FromString

The machinery for overloading literals uses built-ins for the conversion functions.

Reflection

  1. module Agda.Builtin.Reflection

The reflection machinery has built-in types for representing Agda programs. See Reflection for a detailed description.

Rewriting

The experimental and totally unsafe rewriting machinery (not to be confused with the rewrite construct) has a built-in REWRITE for the rewriting relation:

  1. postulate __ : {a} {A : Set a} A A Set a
  2. {-# BUILTIN REWRITE __ #-}

This builtin is bound to the builtin equality type from Agda.Builtin.Equality in Agda.Builtin.Equality.Rewrite.

Static values

The STATIC pragma can be used to mark definitions which should be normalised before compilation. The typical use case for this is to mark the interpreter of an embedded language as STATIC:

  1. {-# STATIC <Name> #-}

Strictness

  1. module Agda.Builtin.Strict

There are two primitives for controlling evaluation order:

  1. primitive
  2. primForce : {a b} {A : Set a} {B : A Set b} (x : A) (∀ x B x) B x
  3. primForceLemma : {a b} {A : Set a} {B : A Set b} (x : A) (f : x B x) primForce x f f x

where _≡_ is the built-in equality. At compile-time primForce x f evaluates to f x when x is in weak head normal form (whnf), i.e. one of the following:

  • a constructor application

  • a literal

  • a lambda abstraction

  • a type constructor application (data or record type)

  • a function type

  • a universe (Set _)

Similarly primForceLemma x f, which lets you reason about programs using primForce, evaluates to refl when x is in whnf. At run-time, primForce e f is compiled (by the GHC backend) to let x = e in seq x (f x).

For example, consider the following function:

  1. -- pow n a = a 2
  2. pow : Nat Nat Nat
  3. pow zero a = a
  4. pow (suc n) a = pow n (a + a)

There is a space leak here (both for compile-time and run-time evaluation), caused by unevaluated a + a thunks. This problem can be fixed with primForce:

  1. infixr 0 _$!_
  2. _$!_ : {a b} {A : Set a} {B : A Set b} (∀ x B x) x B x
  3. f $! x = primForce x f
  4. -- pow n a = a 2
  5. pow : Nat Nat Nat
  6. pow zero a = a
  7. pow (suc n) a = pow n $! a + a