To decode JSON objects in Elm, we use the `Decode.object*`

functions. This gives a problem when decoding objects with more than eight fields, because these decode functions are only defined up to `Decode.object8`

. For me, decoding large json object is pretty common, so a better solution is needed.

## Naive solution

A solution that I came upon on reddit is to use `Decode.andThen`

and `Decode.succeed`

to make a decoder.

```
import Html exposing (text)
import Json.Decode as Decode exposing
(Decoder, (:=), oneOf, maybe
, string, float, andThen)
-- example json returned by the server (as an elm string)
serverResponse = \"\"\"{"tag": "input", "default": "test"}\"\"\"
type alias Response = { tag : String, default : String }
decodeResponse : Decoder Response
decodeResponse =
("tag" := string) `andThen` (\\tag ->
("default" := string) `andThen` (\\default ->
Decode.succeed (Response tag default)))
main =
Decode.decodeString decodeResponse serverResponse
|> toString
|> text
```

This works, but it’s not great:

- arguments need to be named. this is unwieldy
- many brackets and inline functions
- this looks messy

*Fist on table* There MUST be a better way!

## Enter Applicative Functors

The `andThen`

pattern in the above example seems very regular, and technically it does the job. Maybe it is possible to abstract this pattern (that is, hide it in some function so it’s not visible any more - out of sight, out of mind.)

It turns out that by applying some abstract mathematics, the above example can be simply (simple, not easy) transformed into something much more readable. The trick is to apply Applicative Functors.

### Functor

So, what is a functor? Functor is a concept and name from category theory, famous for its cool but vague words. In Elm, a functor is a type that has a `map`

function defined on it (or this function can be defined.) For instance `List.map : (a -> b) -> List a -> List b`

or `Maybe.map : (a -> b) -> Maybe a -> Maybe b`

. Notice that these function signatures have the same shape: `(a -> b) -> f a -> f b`

(where f is a functor, like `List`

or `Maybe`

.)

So, when a function `map`

with the signature `(a -> b) -> f a -> f b`

can be defined, the type f is probably a functor.

To be sure, the `map`

function also has to satisfy the Functor Law. These need to be checked by the programmer. See if you can prove this for Maybe and List.

`map identity f == identity f`

### Applicative

Applicative is a specialisation of a functor. That means that any applicative is also a functor, but the inverse need not be true. Where Functor has the characteristic function `map`

, applicative has two functions: `andMap : f (a -> b) -> f a -> f b`

and `pure : a -> f a`

(where, for lack of a better letter, f stands for Applicative.)

The `pure`

function puts any type into an Applicative. examples of this are `Just : a -> Maybe a`

or `(\\x -> [x]) : a -> List a`

.

For `List`

the `andMap`

function can be defined as follows:

```
andMap : List (a -> b) -> List a -> List b
andMap fs xs = List.concat <| List.map (\\f -> List.map f xs) fs
-- easier version: requires almost no thinking.
andMap' : List (a -> b) -> List a -> List b
andMap' = List.map2 (<|)
```

Again, there are some laws:

```
-- identity
pure identity `andMap` v = v
-- composition
pure (<<) `andMap` u `andMap` v `andMap` w
= u `andMap` (v `andMap `w`)
-- homomorphism
pure f `andMap` pure x = pure (f x)
-- interchange
u `andMap` (pure y) = pure ((<|) y) `andMap` u
```

These laws are a lot more technical. Luckily, in day-to-day Elm they never really pop up, because category theory is not (yet) a leading design pattern. If you like this, go try some haskell; Haskell knowledge can be very useful in Elm (and vice versa.)

The use of this abstract pattern may not be clear initially. When, in practice, do you get a List of functions? And even if you encounter it at some point, defining this function with concat and map is not that difficult. The power lies in the generality. The shortcut version of this function is also quite handy.

## Solving problems

So, that is the theoretical part. What is the idea here? Remember that the goal is to decode a certain amount of elements and feed them to a function. The example with `andThen`

at the top first decodes all the arguments and then applies them. This pattern leads to a lot of extra syntax and requires naming. Instead, the composition characteristic of andMap can be used to start with a decoder of a function, decode and apply one argument, and then recurse for however many arguments are needed.

More concretely, a function is needed of the type `Decoder (a -> b) -> Decoder a -> Decoder b`

(i.e. andMap for Decoder.) Therefore, Decoder has to be an Applicative Functor. Let’s see how the functions `map`

, `andMap`

and `pure`

can be implemented.

`Decoder.map : (a -> b) -> Decoder a -> Decoder b`

is already defined in `Json.Decode`

, so Decode is a functor. The type signature for `pure`

is the same as for `Decode.succeed`

. The only challenge is `andMap`

.

It is not very obvious, but with some type puzzeling:

```
-- function application
(<|) : (a -> b) -> a -> b
f <| x = f x
-- now substitute (<|) as the first argument to Decode.object2
Decode.object2 : (c -> d -> value)
-> Decoder c
-> Decoder d
-> Decoder value
-- gives
andMap : Decoder (a -> b) -> Decoder a -> Decoder b
andMap = Decode.object2 (<|)
```

Not obvious. Hints are that this function takes two decoder arguments (for the function and an argument) and that its type signature looks very similar to `List.map2 : (a -> b -> value) -> List a -> List b -> List value`

.

Great, Decoder is an applicative. Let’s apply it. The example at the start of this post can now be rewritten as follows (I’ve added the type of every line in the decoder as a comment.)

```
serverResponse = \"\"\"{"tag": "input", "default": "test"}\"\"\"
type alias Response = { tag : String, default : String }
decodeResponse : Decoder Response
decodeResponse =
Decode.succeed Response -- Decoder (String -> (String -> Response))
`andMap` ("tag" := string) -- Decoder (String -> Response)
`andMap` ("default" := string) -- Decoder Response
```

Now, depending on your stance toward infix operators, you can clean this up further using

```
(|:) = andMap
decodeResponse : Decoder Response
decodeResponse =
Decode.succeed Response
|: ("tag" := string)
|: ("default" := string)
```

This is visually pleasing and easilly extendable. The usual argument that infix symbolic operators obfuscate code doesn’t really hold here in my opinion. Its effect (within the context of decoding a JSON object) is easilly inferable from the code.

## conclusion

Using a bit of category theory (the branch of mathematics that studies structures like functors and applicatives) it is possible to significantly improve code.