As usual, this is a Literate Haskell file, with the obligatory header:

```
> {-# LANGUAGE StandaloneDeriving, TypeInType, TypeOperators, GADTs,
> TypeFamilies, UndecidableInstances #-}
> {-# OPTIONS_GHC -Wincomplete-patterns #-}
```

`> module VecList where`

```
> import Data.Kind ( Type )
> import Prelude hiding ( concat, (++) )
```

```
> data Nat where
> Zero :: Nat
> Succ :: Nat -> Nat
```

```
> type family (a :: Nat) + (b :: Nat) :: Nat where
> Zero + b = b
> Succ a + b = Succ (a + b)
> infixl 6 +
```

```
> type family (a :: Nat) * (b :: Nat) :: Nat where
> Zero * b = Zero
> Succ a * b = b + (a * b)
> infixl 7 *
```

```
> data Vec :: Nat -> Type -> Type where
> Nil :: Vec Zero a
> (:>) :: a -> Vec n a -> Vec (Succ n) a
> infixr 5 :>
```

`> deriving instance Show a => Show (Vec n a)`

```
> (++) :: Vec n a -> Vec m a -> Vec (n + m) a
> Nil ++ ys = ys
> (x :> xs) ++ ys = x :> (xs ++ ys)
> infixr 5 ++
```

Consider this standard-library function:

```
concat :: [[a]] -> [a]
concat [] = []
concat (xs : xss) = xs ++ concat xss
```

This function takes a list of lists and flattens it to just one list. So `concat [[1,2], [3], [4, 5, 6]]`

is `[1,2,3,4,5,6]`

.

Here’s how we might try to write it over `Vec`

s:

```
> concatRect :: Vec m (Vec n a) -> Vec (m * n) a
> concatRect Nil = Nil
> concatRect (xs :> xss) = xs ++ concatRect xss
```

Note that we’re using type-level multiplication now, with `*`

. This type family is defined above, in the introduction. (Its definition requires `UndecidableInstances`

. That flag disables GHC’s very simplistic termination checker for type families. Enabling the extension means that GHC might not terminate when trying to compile your file. But that’s a risk we’ll have to take.)

The problem with `concatRect`

is that it’s limiting. It allows us only to concatenate a *rectangular* arrangement of elements, where each `Vec`

stored within the larger `Vec`

has the same length `n`

. This function is thus inapplicable to our initial example with the numbers 1 through 6.

In order to contemplate a more general `concat`

, we need a new structure, for holding lists of `Vec`

s of uneven lengths. But we still want the structure’s type to record their lengths, so that we can sum all the lengths in the type of `concat`

. To do this, we’ll need type-level lists:

```
> data VecList :: [Nat] -> Type -> Type where
> VLNil :: VecList '[] a
> (:>>) :: Vec n a -> VecList ns a -> VecList (n ': ns) a
> infixr 5 :>>
```

The `VecList`

type is indexed by a type-level *list* of type-level `Nat`

s. Each element in the list is the index for one of the `Vec`

s stored in the list. (All elements have the same type `a`

.) In the `VLNil`

empty list case, we see that the type-level list of lengths is empty. (GHC requires that the promoted nil constructor and the promoted cons constructor are *always* written with their preceding ticks, as we see above.) In the `:>>`

case, we get a `Vec n a`

, a `VecList ns a`

(that is, a `VecList`

indexed by the type-level list of type-level `Nat`

s, which we’re calling `ns`

), producing a `VecList (n ': ns) a`

. That is, the result type just conses the new `n`

onto the list `ns`

.

We can now write the following translation of our original example:

`> stuffs = (1 :> 2 :> Nil) :>> (3 :> Nil) :>> (4 :> 5 :> 6 :> Nil) :>> VLNil`

GHCi can tell us

```
λ> :t stuffs
stuffs
:: VecList
'['Succ ('Succ 'Zero), 'Succ 'Zero, 'Succ ('Succ ('Succ 'Zero))]
Integer
```

That should be no surprise. The index to the type of `stuffs`

is `'[2,1,3]`

, corresponding to the lengths of the constituent elements of `stuffs`

.

Writing `concat`

is now relatively easy:

```
> type family Sum (ns :: [Nat]) :: Nat where
> Sum '[] = Zero
> Sum (n ': ns) = n + Sum ns
```

```
> concat :: VecList ns a -> Vec (Sum ns) a
> concat VLNil = Nil
> concat (xs :>> xss) = xs ++ concat xss
```

Note that, in the type of `concat`

, we must use a new type family `Sum`

that sums up all the elements in `ns`

. It would be ill-kinded to say `Vec ns a`

, because `Vec`

is indexed by a `Nat`

, but `ns`

is a `[Nat]`

.