# Types and Functions¶

## Primitive Types¶

Idris defines several primitive types: `Int`

, `Integer`

and
`Float`

for numeric operations, `Char`

and `String`

for text
manipulation, and `Ptr`

which represents foreign pointers. There are
also several data types declared in the library, including `Bool`

,
with values `True`

and `False`

. We can declare some constants with
these types. Enter the following into a file `Prims.idr`

and load it
into the Idris interactive environment by typing ```
idris
Prims.idr
```

:

```
module Prims
x : Int
x = 42
foo : String
foo = "Sausage machine"
bar : Char
bar = 'Z'
quux : Bool
quux = False
```

An Idris file consists of an optional module declaration (here
`module Prims`

) followed by an optional list of imports and a
collection of declarations and definitions. In this example no imports
have been specified. However Idris programs can consist of several
modules and the definitions in each module each have their own
namespace. This is discussed further in Section
Modules and Namespaces). When writing Idris programs both the order in which
definitions are given and indentation are significant. Functions and
data types must be defined before use, incidentally each definition must
have a type declaration, for example see `x : Int`

, ```
foo :
String
```

, from the above listing. New declarations must begin at the
same level of indentation as the preceding declaration.
Alternatively, a semicolon `;`

can be used to terminate declarations.

A library module `prelude`

is automatically imported by every
Idris program, including facilities for IO, arithmetic, data
structures and various common functions. The prelude defines several
arithmetic and comparison operators, which we can use at the prompt.
Evaluating things at the prompt gives an answer, and the type of the
answer. For example:

```
*prims> 6*6+6
42 : Int
*prims> x == 6*6+6
True : Bool
```

All of the usual arithmetic and comparison operators are defined for
the primitive types. They are overloaded using type classes, as we
will discuss in Section Type Classes and can be extended to
work on user defined types. Boolean expressions can be tested with the
`if...then...else`

construct, for example:

```
*prims> if x == 6 * 6 + 6 then "The answer!" else "Not the answer"
"The answer!" : String
```

## Data Types¶

Data types are declared in a similar way and with similar syntax to Haskell. Natural numbers and lists, for example, can be declared as follows:

```
data Nat = Z | S Nat -- Natural numbers
-- (zero and successor)
data List a = Nil | (::) a (List a) -- Polymorphic lists
```

The above declarations are taken from the standard library. Unary
natural numbers can be either zero (`Z`

), or the successor of
another natural number (`S k`

). Lists can either be empty (`Nil`

)
or a value added to the front of another list (`x :: xs`

). In the
declaration for `List`

, we used an infix operator `::`

. New
operators such as this can be added using a fixity declaration, as
follows:

```
infixr 10 ::
```

Functions, data constructors and type constructors may all be given
infix operators as names. They may be used in prefix form if enclosed
in brackets, e.g. `(::)`

. Infix operators can use any of the
symbols:

```
:+-*\/=.?|&><!@$%^~#
```

Some operators built from these symbols can’t be user defined. These are
`:`

, `=>`

, `->`

, `<-`

, `=`

, `?=`

, `|`

, `**`

,
`==>`

, `\`

, `%`

, `~`

, `?`

, and `!`

.

## Functions¶

Functions are implemented by pattern matching, again using a similar
syntax to Haskell. The main difference is that Idris requires type
declarations for all functions, using a single colon `:`

(rather
than Haskell’s double colon `::`

). Some natural number arithmetic
functions can be defined as follows, again taken from the standard
library:

```
-- Unary addition
plus : Nat -> Nat -> Nat
plus Z y = y
plus (S k) y = S (plus k y)
-- Unary multiplication
mult : Nat -> Nat -> Nat
mult Z y = Z
mult (S k) y = plus y (mult k y)
```

The standard arithmetic operators `+`

and `*`

are also overloaded
for use by `Nat`

, and are implemented using the above functions.
Unlike Haskell, there is no restriction on whether types and function
names must begin with a capital letter or not. Function names
(`plus`

and `mult`

above), data constructors (`Z`

, `S`

,
`Nil`

and `::`

) and type constructors (`Nat`

and `List`

) are
all part of the same namespace. We can test these functions at the
Idris prompt:

```
Idris> plus (S (S Z)) (S (S Z))
4 : Nat
Idris> mult (S (S (S Z))) (plus (S (S Z)) (S (S Z)))
12 : Nat
```

Note

Idris automatically desugars the `Nat`

representation into a
more human readable format. The result of `plus (S (S Z)) (S (S Z))`

is actually `(S (S (S (S Z))))`

which is the Integer 4. This can be
checked at the Idris prompt:

```
Idris> (S (S (S (S Z))))
4 : Nat
```

Like arithmetic operations, integer literals are also overloaded using type classes, meaning that we can also test the functions as follows:

```
Idris> plus 2 2
4 : Nat
Idris> mult 3 (plus 2 2)
12 : Nat
```

You may wonder, by the way, why we have unary natural numbers when our
computers have perfectly good integer arithmetic built in. The reason
is primarily that unary numbers have a very convenient structure which
is easy to reason about, and easy to relate to other data structures
as we will see later. Nevertheless, we do not want this convenience to
be at the expense of efficiency. Fortunately, Idris knows about
the relationship between `Nat`

(and similarly structured types) and
numbers. This means it can optimise the representation, and functions
such as `plus`

and `mult`

.

`where`

clauses¶

Functions can also be defined *locally* using `where`

clauses. For
example, to define a function which reverses a list, we can use an
auxiliary function which accumulates the new, reversed list, and which
does not need to be visible globally:

```
reverse : List a -> List a
reverse xs = revAcc [] xs where
revAcc : List a -> List a -> List a
revAcc acc [] = acc
revAcc acc (x :: xs) = revAcc (x :: acc) xs
```

Indentation is significant — functions in the `where`

block must be
indented further than the outer function.

Note

Scope

Any names which are visible in the outer scope are also visible in
the `where`

clause (unless they have been redefined, such as `xs`

here). A name which appears only in the type will be in scope in the
`where`

clause if it is a *parameter* to one of the types, i.e. it
is fixed across the entire structure.

As well as functions, `where`

blocks can include local data
declarations, such as the following where `MyLT`

is not accessible
outside the definition of `foo`

:

```
foo : Int -> Int
foo x = case isLT of
Yes => x*2
No => x*4
where
data MyLT = Yes | No
isLT : MyLT
isLT = if x < 20 then Yes else No
```

In general, functions defined in a `where`

clause need a type
declaration just like any top level function. However, the type
declaration for a function `f`

*can* be omitted if:

`f`

appears in the right hand side of the top level definition- The type of
`f`

can be completely determined from its first application

So, for example, the following definitions are legal:

```
even : Nat -> Bool
even Z = True
even (S k) = odd k where
odd Z = False
odd (S k) = even k
test : List Nat
test = [c (S 1), c Z, d (S Z)]
where c x = 42 + x
d y = c (y + 1 + z y)
where z w = y + w
```

## Dependent Types¶

### First Class Types¶

In Idris, types are a first class language construct, meaning that they can be computed and manipulated (and passed to functions) just like any other language construct. For example, we could write a function which computes a type:

```
isSingleton : Bool -> Type
isSingleton True = Nat
isSingleton False = List Nat
```

This function calculates the appropriate type from a `Bool`

which flags
whether the type should be a singleton or not. We can use this function
to calculate a type anywhere that a type can be used. For example, it
can be used to calculate a return type:

```
mkSingle : (x : Bool) -> isSingleton x
mkSingle True = 0
mkSingle False = []
```

Or it can be used to have varying input types. The following function
calculates either the sum of a list of `Nat`

, or returns the given
`Nat`

, depending on whether the singleton flag is true:

```
sum : (single : Bool) -> isSingleton single -> Nat
sum True x = x
sum False [] = 0
sum False (x :: xs) = x + sum False xs
```

### Vectors¶

A standard example of a dependent data type is the type of “lists with
length”, conventionally called vectors in the dependent type
literature. They are available as part of the Idris library, by
importing `Data.Vect`

, or we can declare them as follows:

```
data Vect : Nat -> Type -> Type where
Nil : Vect Z a
(::) : a -> Vect k a -> Vect (S k) a
```

Note that we have used the same constructor names as for `List`

.
Ad-hoc name overloading such as this is accepted by Idris,
provided that the names are declared in different namespaces (in
practice, normally in different modules). Ambiguous constructor names
can normally be resolved from context.

This declares a family of types, and so the form of the declaration is
rather different from the simple type declarations above. We
explicitly state the type of the type constructor `Vect`

— it takes
a `Nat`

and a type as an argument, where `Type`

stands for the
type of types. We say that `Vect`

is *indexed* over `Nat`

and
*parameterised* by `Type`

. Each constructor targets a different part
of the family of types. `Nil`

can only be used to construct vectors
with zero length, and `::`

to construct vectors with non-zero
length. In the type of `::`

, we state explicitly that an element of
type `a`

and a tail of type `Vect k a`

(i.e., a vector of length
`k`

) combine to make a vector of length `S k`

.

We can define functions on dependent types such as `Vect`

in the same
way as on simple types such as `List`

and `Nat`

above, by pattern
matching. The type of a function over `Vect`

will describe what
happens to the lengths of the vectors involved. For example, `++`

,
defined as follows, appends two `Vect`

:

```
(++) : Vect n a -> Vect m a -> Vect (n + m) a
(++) Nil ys = ys
(++) (x :: xs) ys = x :: xs ++ ys
```

The type of `(++)`

states that the resulting vector’s length will be
the sum of the input lengths. If we get the definition wrong in such a
way that this does not hold, Idris will not accept the definition.
For example:

```
(++) : Vect n a -> Vect m a -> Vect (n + m) a
(++) Nil ys = ys
(++) (x :: xs) ys = x :: xs ++ xs -- BROKEN
```

When run through the Idris type checker, this results in the following:

```
$ idris vbroken.idr --check
vbroken.idr:9:23:When elaborating right hand side of Vect.++:
When elaborating an application of constructor Vect.:::
Type mismatch between
Vect (k + k) a (Type of xs ++ xs)
and
Vect (plus k m) a (Expected type)
Specifically:
Type mismatch between
plus k k
and
plus k m
```

This error message suggests that there is a length mismatch between
two vectors — we needed a vector of length `k + m`

, but provided a
vector of length `k + k`

.

### The Finite Sets¶

Finite sets, as the name suggests, are sets with a finite number of
elements. They are available as part of the Idris library, by
importing `Data.Fin`

, or can be declared as follows:

```
data Fin : Nat -> Type where
FZ : Fin (S k)
FS : Fin k -> Fin (S k)
```

From the signature, we can see that this is a type constructor that takes a `Nat`

, and produces a type.
So this is not a set in the sense of a collection that is a container of objects,
rather it is the canonical set of unnamed elements, as in “the set of 5 elements,” for example.
Effectively, it is a type that captures integers that fall into the range of zero to `(n - 1)`

where
`n`

is the argument used to instantiate the `Fin`

type.
For example, `Fin 5`

can be thought of as the type of integers between 0 and 4.

Let us look at the constructors in greater detail.

`FZ`

is the zeroth element of a finite set with `S k`

elements;
`FS n`

is the `n+1`

th element of a finite set with `S k`

elements. `Fin`

is indexed by a `Nat`

, which represents the number
of elements in the set. Since we can’t construct an element of an
empty set, neither constructor targets `Fin Z`

.

As mentioned above, a useful application of the `Fin`

family is to
represent bounded natural numbers. Since the first `n`

natural
numbers form a finite set of `n`

elements, we can treat `Fin n`

as
the set of integers greater than or equal to zero and less than `n`

.

For example, the following function which looks up an element in a
`Vect`

, by a bounded index given as a `Fin n`

, is defined in the
prelude:

```
index : Fin n -> Vect n a -> a
index FZ (x :: xs) = x
index (FS k) (x :: xs) = index k xs
```

This function looks up a value at a given location in a vector. The
location is bounded by the length of the vector (`n`

in each case),
so there is no need for a run-time bounds check. The type checker
guarantees that the location is no larger than the length of the
vector, and of course no less than zero.

Note also that there is no case for `Nil`

here. This is because it
is impossible. Since there is no element of `Fin Z`

, and the
location is a `Fin n`

, then `n`

can not be `Z`

. As a result,
attempting to look up an element in an empty vector would give a
compile time type error, since it would force `n`

to be `Z`

.

### Implicit Arguments¶

Let us take a closer look at the type of `index`

:

```
index : Fin n -> Vect n a -> a
```

It takes two arguments, an element of the finite set of `n`

elements,
and a vector with `n`

elements of type `a`

. But there are also two
names, `n`

and `a`

, which are not declared explicitly. These are
*implicit* arguments to `index`

. We could also write the type of
`index`

as:

```
index : {a:Type} -> {n:Nat} -> Fin n -> Vect n a -> a
```

Implicit arguments, given in braces `{}`

in the type declaration,
are not given in applications of `index`

; their values can be
inferred from the types of the `Fin n`

and `Vect n a`

arguments. Any name beginning with a lower case letter which appears
as a parameter or index in a
type declaration, but which is otherwise unbound, will be automatically
bound as an implicit argument. Implicit arguments can still be given
explicitly in applications, using `{a=value}`

and `{n=value}`

, for
example:

```
index {a=Int} {n=2} FZ (2 :: 3 :: Nil)
```

In fact, any argument, implicit or explicit, may be given a name. We
could have declared the type of `index`

as:

```
index : (i:Fin n) -> (xs:Vect n a) -> a
```

It is a matter of taste whether you want to do this — sometimes it can help document a function by making the purpose of an argument more clear.

### “`using`

” notation¶

Sometimes it is useful to provide types of implicit arguments, particularly where there is a dependency ordering, or where the implicit arguments themselves have dependencies. For example, we may wish to state the types of the implicit arguments in the following definition, which defines a predicate on vectors:

```
data Elem : a -> Vect n a -> Type where
Here : {x:a} -> {xs:Vect n a} -> Elem x (x :: xs)
There : {x,y:a} -> {xs:Vect n a} -> Elem x xs -> Elem x (y :: xs)
```

An instance of `Elem x xs`

states that `x`

is an element of
`xs`

. We can construct such a predicate if the required element is
`Here`

, at the head of the vector, or `There`

, in the tail of the
vector. For example:

```
testVec : Vect 4 Int
testVec = 3 :: 4 :: 5 :: 6 :: Nil
inVect : Elem 5 testVec
inVect = There (There Here)
```

If the same implicit arguments are being used a lot, it can make a
definition difficult to read. To avoid this problem, a `using`

block
gives the types and ordering of any implicit arguments which can
appear within the block:

```
using (x:a, y:a, xs:Vect n a)
data Elem : a -> Vect n a -> Type where
Here : Elem x (x :: xs)
There : Elem x xs -> Elem x (y :: xs)
```

#### Note: Declaration Order and `mutual`

blocks¶

In general, functions and data types must be defined before use, since
dependent types allow functions to appear as part of types, and their
reduction behaviour to affect type checking. However, this restriction
can be relaxed by using a `mutual`

block, which allows data types
and functions to be defined simultaneously:

```
mutual
even : Nat -> Bool
even Z = True
even (S k) = odd k
odd : Nat -> Bool
odd Z = False
odd (S k) = even k
```

In a `mutual`

block, first all of the type declarations are added,
then the function bodies. As a result, none of the function types can
depend on the reduction behaviour of any of the functions in the
block.

## I/O¶

Computer programs are of little use if they do not interact with the
user or the system in some way. The difficulty in a pure language such
as Idris — that is, a language where expressions do not have
side-effects — is that I/O is inherently side-effecting. Therefore in
Idris, such interactions are encapsulated in the type `IO`

:

```
data IO a -- IO operation returning a value of type a
```

We’ll leave the definition of `IO`

abstract, but effectively it
describes what the I/O operations to be executed are, rather than how
to execute them. The resulting operations are executed externally, by
the run-time system. We’ve already seen one IO program:

```
main : IO ()
main = putStrLn "Hello world"
```

The type of `putStrLn`

explains that it takes a string, and returns
an element of the unit type `()`

via an I/O action. There is a
variant `putStr`

which outputs a string without a newline:

```
putStrLn : String -> IO ()
putStr : String -> IO ()
```

We can also read strings from user input:

```
getLine : IO String
```

A number of other I/O operations are defined in the prelude, for example for reading and writing files, including:

```
data File -- abstract
data Mode = Read | Write | ReadWrite
openFile : String -> Mode -> IO File
closeFile : File -> IO ()
fread : File -> IO String
fwrite : File -> String -> IO ()
feof : File -> IO Bool
readFile : String -> IO String
```

## “`do`

” notation¶

I/O programs will typically need to sequence actions, feeding the
output of one computation into the input of the next. `IO`

is an
abstract type, however, so we can’t access the result of a computation
directly. Instead, we sequence operations with `do`

notation:

```
greet : IO ()
greet = do putStr "What is your name? "
name <- getLine
putStrLn ("Hello " ++ name)
```

The syntax `x <- iovalue`

executes the I/O operation `iovalue`

, of
type `IO a`

, and puts the result, of type `a`

into the variable
`x`

. In this case, `getLine`

returns an `IO String`

, so `name`

has type `String`

. Indentation is significant — each statement in
the do block must begin in the same column. The `return`

operation
allows us to inject a value directly into an IO operation:

```
return : a -> IO a
```

As we will see later, `do`

notation is more general than this, and
can be overloaded.

## Laziness¶

Normally, arguments to functions are evaluated before the function
itself (that is, Idris uses *eager* evaluation). However, this is
not always the best approach. Consider the following function:

```
ifThenElse : Bool -> a -> a -> a;
ifThenElse True t e = t;
ifThenElse False t e = e;
```

This function uses one of the `t`

or `e`

arguments, but not both
(in fact, this is used to implement the `if...then...else`

construct
as we will see later. We would prefer if *only* the argument which was
used was evaluated. To achieve this, Idris provides a `Lazy`

data type, which allows evaluation to be suspended:

```
data Lazy : Type -> Type where
Delay : (val : a) -> Lazy a
Force : Lazy a -> a
```

A value of type `Lazy a`

is unevaluated until it is forced by
`Force`

. The Idris type checker knows about the `Lazy`

type,
and inserts conversions where necessary between `Lazy a`

and `a`

,
and vice versa. We can therefore write `ifThenElse`

as follows,
without any explicit use of `Force`

or `Delay`

:

```
ifThenElse : Bool -> Lazy a -> Lazy a -> a;
ifThenElse True t e = t;
ifThenElse False t e = e;
```

## Useful Data Types¶

Idris includes a number of useful data types and library functions
(see the `libs/`

directory in the distribution). This chapter
describes a few of these. The functions described here are imported
automatically by every Idris program, as part of `Prelude.idr`

.

`List`

and `Vect`

¶

We have already seen the `List`

and `Vect`

data types:

```
data List a = Nil | (::) a (List a)
data Vect : Nat -> Type -> Type where
Nil : Vect Z a
(::) : a -> Vect k a -> Vect (S k) a
```

Note that the constructor names are the same for each — constructor
names (in fact, names in general) can be overloaded, provided that
they are declared in different namespaces (see Section
Modules and Namespaces), and will typically be resolved according to
their type. As syntactic sugar, any type with the constructor names
`Nil`

and `::`

can be written in list form. For example:

`[]`

means`Nil`

`[1,2,3]`

means`1 :: 2 :: 3 :: Nil`

The library also defines a number of functions for manipulating these
types. `map`

is overloaded both for `List`

and `Vect`

and
applies a function to every element of the list or vector.

```
map : (a -> b) -> List a -> List b
map f [] = []
map f (x :: xs) = f x :: map f xs
map : (a -> b) -> Vect n a -> Vect n b
map f [] = []
map f (x :: xs) = f x :: map f xs
```

For example, given the following vector of integers, and a function to double an integer:

```
intVec : Vect 5 Int
intVec = [1, 2, 3, 4, 5]
double : Int -> Int
double x = x * 2
```

the function `map`

can be used as follows to double every element in
the vector:

```
*usefultypes> show (map double intVec)
"[2, 4, 6, 8, 10]" : String
```

You’ll find these examples in `usefultypes.idr`

in the `examples/`

directory. For more details of the functions available on `List`

and
`Vect`

, look in the library files:

`libs/prelude/Prelude/List.idr`

`libs/base/Data/List.idr`

`libs/base/Data/Vect.idr`

`libs/base/Data/VectType.idr`

Functions include filtering, appending, reversing, and so on. Also remember that Idris is still in development, so if you don’t see the function you need, please feel free to add it and submit a patch!

#### Aside: Anonymous functions and operator sections¶

There are actually neater ways to write the above expression. One way would be to use an anonymous function:

```
*usefultypes> show (map (\x => x * 2) intVec)
"[2, 4, 6, 8, 10]" : String
```

The notation `\x => val`

constructs an anonymous function which takes
one argument, `x`

and returns the expression `val`

. Anonymous
functions may take several arguments, separated by commas,
e.g. `\x, y, z => val`

. Arguments may also be given explicit types,
e.g. `\x : Int => x * 2`

, and can pattern match,
e.g. `\(x, y) => x + y`

. We could also use an operator section:

```
*usefultypes> show (map (* 2) intVec)
"[2, 4, 6, 8, 10]" : String
```

`(*2)`

is shorthand for a function which multiplies a number
by 2. It expands to `\x => x * 2`

. Similarly, `(2*)`

would expand
to `\x => 2 * x`

.

### Maybe¶

`Maybe`

describes an optional value. Either there is a value of the
given type, or there isn’t:

```
data Maybe a = Just a | Nothing
```

`Maybe`

is one way of giving a type to an operation that may
fail. For example, looking something up in a `List`

(rather than a
vector) may result in an out of bounds error:

```
list_lookup : Nat -> List a -> Maybe a
list_lookup _ Nil = Nothing
list_lookup Z (x :: xs) = Just x
list_lookup (S k) (x :: xs) = list_lookup k xs
```

The `maybe`

function is used to process values of type `Maybe`

,
either by applying a function to the value, if there is one, or by
providing a default value:

```
maybe : Lazy b -> (a -> b) -> Maybe a -> b
```

Note that the type of the first argument is `Lazy b`

rather than
simply `b`

. Since the default value might not be used, we mark it as
`Lazy`

in case it is a large expression where evaluating it then
discarding it would be wasteful.

### Tuples¶

Values can be paired with the following built-in data type:

```
data Pair a b = MkPair a b
```

As syntactic sugar, we can write `(a, b)`

which, according to
context, means either `Pair a b`

or `MkPair a b`

. Tuples can
contain an arbitrary number of values, represented as nested pairs:

```
fred : (String, Int)
fred = ("Fred", 42)
jim : (String, Int, String)
jim = ("Jim", 25, "Cambridge")
```

### Dependent Pairs¶

Dependent pairs allow the type of the second element of a pair to depend on the value of the first element. Traditionally, these are referred to as “sigma types”:

```
data Sigma : (a : Type) -> (P : a -> Type) -> Type where
MkSigma : {P : a -> Type} -> (x : a) -> P x -> Sigma a P
```

Again, there is syntactic sugar for this. `(a : A ** P)`

is the type
of a pair of A and P, where the name `a`

can occur inside `P`

.
`( a ** p )`

constructs a value of this type. For example, we can
pair a number with a `Vect`

of a particular length.

```
vec : (n : Nat ** Vect n Int)
vec = (2 ** [3, 4])
```

If you like, you can write it out the long way, the two are precisely equivalent.

```
vec : Sigma Nat (\n => Vect n Int)
vec = MkSigma 2 [3, 4]
```

The type checker could of course infer the value of the first element
from the length of the vector. We can write an underscore `_`

in
place of values which we expect the type checker to fill in, so the
above definition could also be written as:

```
vec : (n : Nat ** Vect n Int)
vec = (_ ** [3, 4])
```

We might also prefer to omit the type of the first element of the pair, since, again, it can be inferred:

```
vec : (n ** Vect n Int)
vec = (_ ** [3, 4])
```

One use for dependent pairs is to return values of dependent types
where the index is not necessarily known in advance. For example, if
we filter elements out of a `Vect`

according to some predicate, we
will not know in advance what the length of the resulting vector will
be:

```
filter : (a -> Bool) -> Vect n a -> (p ** Vect p a)
```

If the `Vect`

is empty, the result is easy:

```
filter p Nil = (_ ** [])
```

In the `::`

case, we need to inspect the result of a recursive call
to `filter`

to extract the length and the vector from the result. To
do this, we use `with`

notation, which allows pattern matching on
intermediate values:

```
filter p (x :: xs) with (filter p xs)
| ( _ ** xs' ) = if (p x) then ( _ ** x :: xs' ) else ( _ ** xs' )
```

We will see more on `with`

notation later.

### Records¶

*Records* are data types which collect several values (the record’s
*fields*) together. Idris provides syntax for defining records and
automatically generating field access and update functions. Unlike
the syntax used for data structures, records in Idris follow a
different syntax to that seen with Haskell. For example, we can
represent a person’s name and age in a record:

```
record Person where
constructor MkPerson
firstName, middleName, lastName : String
age : Int
fred : Person
fred = MkPerson "Fred" "Joe" "Bloggs" 30
```

The constructor name is provided using the `constructor`

keyword,
and the *fields* are then given which are in an indented block
following the where keyword (here, `firstName`

, `middleName`

,
`lastName`

, and `age`

). You can declare multiple fields on a
single line, provided that they have the same type. The field names
can be used to access the field values:

```
*record> firstName fred
"Fred" : String
*record> age fred
30 : Int
*record> :t firstName
firstName : Person -> String
```

We can also use the field names to update a record (or, more precisely, produce a copy of the record with the given fields updated):

```
*record> record { firstName = "Jim" } fred
MkPerson "Jim" "Joe" "Bloggs" 30 : Person
*record> record { firstName = "Jim", age = 20 } fred
MkPerson "Jim" "Joe" "Bloggs" 20 : Person
```

The syntax `record { field = val, ... }`

generates a function which
updates the given fields in a record.

Records, and fields within records, can have dependent types. Updates are allowed to change the type of a field, provided that the result is well-typed.

```
record Class where
constructor ClassInfo
students : Vect n Person
className : String
```

It is safe to update the `students`

field to a vector of a different
length because it will not affect the type of the record:

```
addStudent : Person -> Class -> Class
addStudent p c = record { students = p :: students c } c
```

```
*record> addStudent fred (ClassInfo [] "CS")
ClassInfo [MkPerson "Fred" "Joe" "Bloggs" 30] "CS" : Class
```

#### Nested record update¶

Idris also provides a convenient syntax for accessing and updating
nested records. For example, if a field is accessible with the
expression `c (b (a x))`

, it can be updated using the following
syntax:

```
record { a->b->c = val } x
```

This returns a new record, with the field accessed by the path
`a->b->c`

set to `x`

. The syntax is first class, i.e. ```
record {
a->b->c = val }
```

itself has a function type. Symmetrically, the field
can also be accessed with the following syntax:

```
record { a->b->c } x
```

### Dependent Records¶

Records can also be dependent on values. Records *parameters*, which
are not subject to field updates. The parameters appear as arguments
to the resulting type, and are written following the record type
name. For example, a pair type could be defined as follows:

```
record Prod a b where
constructor Times
fst : a
snd : b
```

Using the class record from the original introduction to records. The
size of the class can be restricted using a `Vect`

and the size
promoted to the type level by parameterising the record with the size.
Foe example:

```
record SizedClass (size : Nat) where
constructor SizedClassInfo
students : Vect size Person
className : String
```

**Note** that it is no longer possible to use the `addStudent`

method from earlier as that would change the size of the class. To provide an add student the function must specify in the type that the size of the class has been increased by one. As the size if specified using natural numbers, the new value can be incremented using the successor constructor.

```
addStudent : Person -> SizedClass n -> SizedClass (S n)
addStudent p c = record { students = p :: students c } c
```

## More Expressions¶

`let`

bindings¶

Intermediate values can be calculated using `let`

bindings:

```
data Person = MkPerson String Int
showPerson : Person -> String
showPerson p = let MkPerson name age = p in
name ++ " is " ++ show age ++ " years old"
```

We can do simple pattern matching in `let`

bindings too. For
example, we can extract fields from a record as follows, as well as by
pattern matching at the top level:

```
data Person = MkPerson String Int
showPerson : Person -> String
showPerson p = let MkPerson name age = p in
name ++ " is " ++ show age ++ " years old"
```

### List comprehensions¶

Idris provides *comprehension* notation as a convenient shorthand
for building lists. The general form is:

```
[ expression | qualifiers ]
```

This generates the list of values produced by evaluating the
`expression`

, according to the conditions given by the comma
separated `qualifiers`

. For example, we can build a list of
Pythagorean triples as follows:

```
pythag : Int -> List (Int, Int, Int)
pythag n = [ (x, y, z) | z <- [1..n], y <- [1..z], x <- [1..y],
x*x + y*y == z*z ]
```

The `[a..b]`

notation is another shorthand which builds a list of
numbers between `a`

and `b`

. Alternatively `[a,b..c]`

builds a
list of numbers between `a`

and `c`

with the increment specified
by the difference between `a`

and `b`

. This works for any numeric
type, using the `count`

function from the prelude.

`case`

expressions¶

Another way of inspecting intermediate values of *simple* types is to
use a `case`

expression. The following function, for example, splits
a string into two at a given character:

```
splitAt : Char -> String -> (String, String)
splitAt c x = case break (== c) x of
(x, y) => (x, strTail y)
```

`break`

is a library function which breaks a string into a pair of
strings at the point where the given function returns true. We then
deconstruct the pair it returns, and remove the first character of the
second string.

A `case`

expression can match several cases, for example, to inspect
an intermediate value of type `Maybe a`

. Recall `list_lookup`

which looks up an index in a list, returning `Nothing`

if the index
is out of bounds. We can use this to write `lookup_default`

, which
looks up an index and returns a default value if the index is out of
bounds:

```
lookup_default : Nat -> List a -> a -> a
lookup_default i xs def = case list_lookup i xs of
Nothing => def
Just x => x
```

If the index is in bounds, we get the value at that index, otherwise we get a default value:

```
*usefultypes> lookup_default 2 [3,4,5,6] (-1)
5 : Integer
*usefultypes> lookup_default 4 [3,4,5,6] (-1)
-1 : Integer
```

**Restrictions:** The `case`

construct is intended for simple
analysis of intermediate expressions to avoid the need to write
auxiliary functions, and is also used internally to implement pattern
matching `let`

and lambda bindings. It will *only* work if:

- Each branch
*matches*a value of the same type, and*returns*a value of the same type.

- Each branch
- The type of the result is “known”. i.e. the type of the expression
can be determined

*without*type checking the`case`

-expression itself.