Invoices 2: functors and monads in action
Tags: functional, elm
Published: 2019-02-15 15:53:57

---
title: Invoices 2: functors and monads in action
published: true
series: Elm invoice
description: 
tags: #fp, #Elm
---

Considering my last post in this series didn't attract a lot of attention, I've decided to keep it a bit short. If you're interested in writing invoices in Elm, I've made a public [repository](https://gitlab.com/DrBearhands/elm-invoice). I'm using it myself, but at the time of writing it certainly still requires some polishing up.

So let's instead focus on what everybody seems to care about the most, functors and monads.


```elm
type ColumnSize
  = [...]

columnSizeToString : ColumnSize -> String
columnSizeToString gs = [...]


columns : List (Html msg, ColumnSize) -> Html msg
columns cs =
  let
    columnSizes : String
    columnSizes =
      List.map ( columnSizeToString << Tuple.second ) cs
      |> List.intersperse " "
      |> String.concat

    inDiv : Html msg -> Html msg
    inDiv element = div [] [element]
  in
    div
      [ style "display" "grid"
      , style "grid-template-columns" columnSizes
      ]
      ( List.map ( inDiv << Tuple.first ) cs )

```

What's going on here? 

The function `columns` puts multiple elements into columns, using `display: grid;`. 

I decided I wanted to have every column dictate its own width. So rather than passing a list of `Html msg`, we pass a list of `(Html msg, ColumnSize)`. By coupling elements with their widths into tuples, we ensure that we have exactly as many widths as columns.

`ColumnSize` is a type I have declared previously denoting how wide the column should be (e.g. `1fr` or `50px`). I'm using `ColumnSize` rather than `String` so the correctness of the argument is checked at compile time. If I'd used `String`, I could have made a column that is `"7 kg"` long, which would result in a silent error at runtime rather than a loud and obnoxious one at compile time.

-------------

Now let's look at `columnSizes`. It constructs a string denoting the grid's column template, using the list of tuples given as input.

This is where functors come into play. As we've [seen previously](https://dev.to/drbearhands/functors-monads-and-better-functions-26f3), a functor is any *unary type constructor* which has a map function. This is the case for lists: a lists by itself is not a type, but e.g. a list of strings is, and it has a map function that is applies a function to all elements of the list, returning a new list.

That is exactly what happens here:
```elm
List.map ( columnSizeToString << Tuple.second ) cs
```
we create a function by composing `columnSizeToString` after `Tuple.second`, this function is passed to `List.map`, and the resulting function is applied over cs, the list of tuples that was input of the parent function.

So, for each element of cs (a tuple `(Html msg, ColumnSize)`), we first apply `Tuple.second`, the first part of the composition. This returns the second element of the tuple (a `ColumnSize`). We feed that to the second element of the composition, `columnSizeToString`, which returns a string. The result of the whole expression is therefore a `List String`.

In the next line:
```elm
|> List.intersperse " "
```
we *pipe* the result of the previous expression (out list of strings) into `List.intersperse " "`, which intersperses space elements into our list. 

Finally:
```elm
|> String.concat
```
we pipe into `String.concat`, which turns a list of strings into a single string.

-------------

Now, let's look at some code were we use the *monadic* properties of a list. This is a snippet from inside the `keyValueLayout`.

```elm
entryLayout : List (String, String) -> Html msg
    entryLayout entry =
      case entry of
        [] -> div [] []
        (headerKey, headerValue) :: entryRemainder ->
          entryHeaderLayout headerKey headerValue
            :: List.map entryBodyLayout entryRemainder
            |> List.map (\(a, b) -> [a, b])
            |> List.concat
            |> div
              [ style "display" "grid"
              , style "grid-template-columns" "2fr 5fr"
              , style "grid-column-gap" "10px"
              ]

entryHeaderLayout : String -> String -> (Html msg, Html msg)
entryHeaderLayout k v = [...]
entryBodyLayout : ( String, String ) -> (Html msg, Html msg)
entryBodyLayout (k, v) = [...]
```

This code turns pairs of strings into a grid element with 2 neatly aligned columns.

The following lines:
```elm
entryHeaderLayout headerKey headerValue
  :: List.map entryBodyLayout entryRemainder
```
create a list with type `List (Html msg, Html msg)`. They are not particularly interesting so I won't delve into them further.

Rather than a list of tuples, we need a list that looks like `[key1, value1, key2, value2,...]`, as that is what a grid element needs as children. We can turn a tuple into a list using `\(a, b) -> [a, b]`, and we could use the `map` function, but that would leave us with a list of lists of elements, which is not what we want.

Because a list is a monad, we *know* that we can 'bind' a function.
So a function of type `type1 -> List type2`, which is just the type of `\(a, b) -> [a, b]`, can be 'bound' so that a `List type1` can be turned into a `List type2`. Essentially, a flat map. This is what we want! In our case, `type1` is `(Html msg, Html msg)` and `type2` is `Html msg`.

List gives us monadic properties with its `concat` function, which flattens a `List (List a)` into `List a`. 

Because we already have `map`, we can simply flatten after mapping, which is what we do here:

```elm
|> List.map (\(a, b) -> [a, b])
|> List.concat
```

That's it! All it takes to be a monad: a map and a flat map function. 

<small><sub>Okay technically you also need a singleton `a -> F a` function but that one is usually trivial.</sub></small>