# Grids

Grids can have an arbitrary amount of dimensions, specified by a type-level
list of `Nat`

s. They're backed by a single contiguous Vector and gain the associated performance benefits. Currently
only boxed immutable vectors are supported, but let me know if you need other variants.

Here's how we might represent a Tic-Tac-Toe board:

```
data Piece = X | O deriving Show
toPiece n = if even n then X
else O
ticTacToe :: Grid [3, 3] Piece
ticTacToe = generate toPiece
```

You can collapse the grid down to nested lists! The output type of `toNestedLists`

depends on your dimensions, e.g.:

`Grid [3, 3] Piece`

will generate: `[[Piece]]`

`Grid [2, 2, 2] Char`

will generate: `[[[Char]]]`

- ...etc

```
λ> toNestedLists ticTacToe
[ [X,O,X]
, [O,X,O]
, [X,O,X]]
```

You can even create a grid from nested lists! `fromNestedLists`

returns a grid
if possible, or `Nothing`

if the provided lists don't match the structure of
the grid you specify:

```
λ> fromNestedLists [[1, 2], [3, 4]] :: Maybe (Grid '[2, 2] Int)
Just (Grid [[1,2]
,[3,4]])
λ> fromNestedLists [[1], [2]] :: Maybe (Grid '[2, 2] Int)
Nothing
```

Grids are Representable Functors, Applicatives, Foldable, and are Traversable!

You can do things like piecewise addition using their applicative instance:

```
λ> let g = generate id :: Grid '[2, 3] Int
λ> g
(Grid [[0,1,2]
,[3,4,5]])
λ> liftA2 (+) g g
(Grid [[0,2,4]
,[6,8,10]])
λ> liftA2 (*) g g
(Grid [[0,1,4]
,[9,16,25]])
```

## Indexing

You can index into a grid using the `Coord`

type family. The number of
coordinates you need depends on the shape of the grid. The Coord is stitched
together using the `:#`

constructor from 1 or more `Finite`

values. Each Finite
value is scoped to the size of its dimension, so you'll need to prove that each
index is within range (or just use `finite`

to wrap an `Integer`

and the
compiler will trust you). Here's the type of Coord for a few different Grids:

```
Coord '[1] == Finite 1
Coord '[1, 2] == Finite 1 :# Finite 2
Coord '[1, 2, 3] == Finite 1 :# Finite 2 :# Finite 3
```

You can get a value at an index out using `index`

from `Data.Functor.Rep`

:

```
λ> let g = generate id :: Grid '[2, 3] Int
λ> g
(Grid [[0,1,2]
,[3,4,5]])
λ> g `index` (1 :# 1)
4
λ> g `index` (1 :# 0)
3
λ> g `index` (0 :# 2)
2
```

You can also use the `cell`

Lens from `Data.Grid.Lens`

to access and mutate
indices:

```
λ> g ^. cell (0 :# 1)
1
λ> g & cell (0 :# 1) *~ 1000
(Grid [[0,1000,2],[3,4,5]])
```

## Creation

You can generate a grid by providing a function over the integer position in the grid (`generate`

) or by providing
a function over the coordinate position of the cell (`tabulate`

).

You can also use the `fromList`

and `fromNestedLists`

functions which return a
`Maybe (Grid dims a)`

depending on whether the input list is well formed.

`fromList :: [a] -> Maybe (Grid dims a)`

`fromNestedLists :: NestedLists dims a -> Maybe (Grid dims a)`

`generate :: (Int -> a) -> Grid dims a`

`tabulate :: (Coord dims -> a) -> Grid dims a`

`pure :: a -> Grid dims a`

## Updating

Use either the `cell`

lens, or fmap, applicative, traversable.
For batch updates using the underlying Vector implementation use `(//)`

`(//) :: Grid dims a -> [(Coord dims, a)] -> Grid dims a`