Introduction
See about for some background and motivation.
In this introduction we will start with a look at the type theory underlying Typedefs and in the next section we will show some examples in the S-expression syntax.
Type system
The core theory defines the following rules Typedefs.idrs/TDef
:
0
the empty type;1
the unit type;+
co-product of types (also known as sum-types);×
product of types (also known as tuples);µ
fixpoint operator (also known as recursion);- a, b variables;
a b
application.
With this you define algebraic data types (ADTs) such as:
- Types with a fixed finite number of terms, such as bits (2):
Bool
- Parametric types, such as the optional type:
α → Maybe α
- Recursive types, such as homogeneous lists:
α → List α
(Theoretically, these are least fixpoints of F-algebras. We recommend Bartosz Milewski’s blogpost on F-Algebras to learn about it.)
The units
The theory has two ground terms, from which all concrete types are assembled:
0
the empty type;1
the unit type.
The unit type 1 is the unique type that has only one term, usually denoted as •, a dot.
The zero type 0 is the unique type that has no terms (note: in practice you don’t really need the empty type, but there are theoretic reasons for including it).
Both these types are “units” with respect to the next two type formation rules +
and ×
, in the following sense:
0 + a = a + 0 = a
1 × a = a = a × 1
Note: at the moment, these equalities are not reduced away if you write them down.
OPEN: it is an partially open question still how to deal with normalization of types
Sum and product types
Using the familiar symbols +
to express choice or co-product and ×
for pairing we have the following two constructors:
- The coproduct (or sum) formation rule: for all types a and b,
a + b
is a type; - The product (or tuple) formation rule: for all types a & b,
a × b
is a type.
The coproduct type expresses a choice between the terms of the two argument types.
The product type is the tuple or pair of the two argument types.
Some examples:
- We write
1 + 1
to describe the finite type2
that has two terms, the left and the right unit terms of1
; - The type
2 * 2
is the product of two1 + 1
terms, so a pair of booleans if you wish.
Type variables
Type variables can be used to describe parametric type, such as the optional type.
Given a type x
, 1 + x
is the option or maybe type: its terms are the unit term or a term of type x.
Categorically, this defines the mapping 'x -> 1 + x`, which defines an endofunctor on the category of types.
Recursive types
There is also a 5th type formation rule, “mu”.
µ
fixpoint operator (also known as recursion)
When you apply µ to an algebraic functor, it expresses the fixpoint of that functor. Conceptually, “it closes the recursive type definition”.
For example, the list type, l -> a -> (a * l a) + 1
.
Input Language
We currently use S-expressions as a convenient way to input type definitions.
You can use this from the browser at try.typedefs.com.
Alternatively, you can define types directly in Idris, see Examples.idr.
The Unit Type
In the S-expression language, it is predefined as the string 1
and you can assign a name to it as follows:
(name Unit 1)
Basic (closed) types
Let’s construct a very basic type, the booleans. In typedefs, we think of this as the co-product of two unit types, written as 1 + 1.
A co-product of types expresses a choice between terms of those types.
The equation 1 + 1 = 2 expresses nicely that the co-product of two unit types is isomorphic to a type called 2, that has two possible terms, namely the left or the right •.
Here is an example of such definition of the boolean type.
;; the Boolean type as the co-product of two unit-types
(name Bool (+ 1 1))
This type is called closed because it does not have any free variables. (Note: as explained below, one way to think of these definitions is as endofunctors on typedefs. Closed typedefs are then functors from/to the unit type).
Type variables, basic parametric types
It is also possible to define “endofunctors on types”, such as the “optional” or “maybe” type.
Such a type is called parametric because it takes a typedef α
and constructs a new typedef Maybe α
.
Hence, it is a 1-ary functor from typedefs to typedefs.
α → 1 + α
Here is the definiton:
;; the α → Maybe α type constructor
(name Maybe (+ 1 (var 0)))
The number in (var 0)
is a De Bruijn index.
TODO
That’s it for now, more to be written.
If you want to learn more, you can browse the source code or Try Typedefs!.