# Fantas, Eel, and Specification 16: Extend

12 Jun 2017You’re **still** here? That means you survived `Monad`

! See? Told you it isn’t that scary. It’s nothing we haven’t **already seen**. Well, *today*, we’re going to revisit `Chain`

with one *slight* difference. As we know, `Chain`

takes an `m a`

to an `m b`

with some help from an `a -> m b`

function. It **sequences** our ideas. However, *what if I told you*… we could go **backwards**? Let’s `Extend`

your horizons.

Don’t get too excited; the disappointment of `Contravariant`

will come flooding back! We’re certainly not saying that we have a magical `undo`

for any `Chain`

. What we *are* saying, though, is that there are some types for which we can get from `m a`

to `m b`

via `m a -> b`

. Instead of **finishing** in the context, we **start** in it!

Two questions probably come to mind:

**How**is this useful?- … See question 1?

Well, we’ll be answering **at least** one of those questions today! *Before* that, though, let’s go back to our *old* format and **start** with the **function**:

```
extend :: Extend w => w a ~> (w a -> b) -> w b
```

Notice we’re using

`w`

here. I kid younot, we use`w`

because it looks like an upside-down`m`

, and`m`

was what we used for`Chain`

. It’s literally there to make the whole thing lookback-to-frontandupside-down. I’m told that mathematicians call this ajoke, so dotryto laugh!

*As we said*, it’s `Chain`

going backwards. It even has the same laws backwards! Say hello, once again, to our old friend **associativity**:

```
// RHS: Apply to f THEN chain g
m.chain(f).chain(g)
=== m.chain(x => f(x).chain(g))
// RHS: extend f THEN apply to g
w.extend(f).extend(g)
=== x.extend(w_ => g(w_.extend(f)))
```

Wait, so, if

`extend`

hasassociativity, and if it looks a bit like a`Semigroup`

… (all together now)where’s the?!`Monoid`

It’s just like `chain`

, but backwards. **Everything is backwards**. It’s really the only thing you need to remember!

?thgir ,taen ytterP

So, *aside* from it being backwards, is there anything *useful* about `Extend`

? *Or*, are we just getting a bit tired at this point? **Both**! Hopefully more the former, though…

Let’s start with an old friend, the `Pair`

(or `Writer`

) type. When we `chain`

, we have *total* control over the **output** of our function: we say what we *append* to the **left-hand side**, and what we want the right-hand value to be. There was, however, one thing we *can’t* do: see what was already *in* the left part!

`Pair`

really gave us a wonderful way to achieve **write-only** state, but we had no way of **reading** what we’d written! Wouldn’t it be **great** if we had a `map`

-like function that let us take a **sneaky peek** at the left-hand side? Something like this, perhaps:

```
map :: (m, a) ~> (a -> b) -> (m, b)
-- Just like map, but we get a sneaky peek!
sneakyPeekMap :: (m, a)
~> ((m, a) -> b)
-> (m, b)
```

It’s really just like `map`

, but we get some **context**! Now that we can, whenever we like, take a look at how the left-hand side is doing, we can feed our **hungry adventurer**:

```
//- Sum represents "hunger"
const Adventurer = Pair(Sum)
//+ type User = { name :: String, isHungry :: Bool }
const exampleUser = {
name: 'Tom',
isHungry: false
}
// You get the idea... WorkPair again!
//+ slayDragon :: User -> Adventurer User
const slayDragon = user =>
Adventurer(Sum(100), user)
//+ slayDragon :: User -> Adventurer User
const runFromDragon = user =>
Adventurer(Sum(50), user)
//- Eat IF we're hungry
//+ eat :: User -> Adventurer User
const eat = user =>
user.isHungry
? Adventurer(Sum(-100), {
... user,
isHungry: false
})
: Adventurer(Sum(0), user)
//- How could we know when we're hungry?
//- This function goes the other way...
//+ areWeHungry :: Adventurer User -> User
const areWeHungry =
({ _1: { value: hunger }, _2: user }) =>
hunger > 200
? { ... user, isHungry: true }
: user
// Now, we do a thing, check our hunger,
// and eat if we need to!
// WE ARE SELF-AWARE.
// SKYNET
slayDragon(exampleUser)
.sneakyPeekMap(areWeHungry).chain(eat)
// Pair(Sum(100), not hungry)
.chain(slayDragon)
.sneakyPeekMap(areWeHungry).chain(eat)
// Pair(Sum(200), not hungry)
.chain(runFromDragon)
.sneakyPeekMap(areWeHungry).chain(eat)
// Pair(Sum(150), not hungry)!
```

Just with this `sneakyPeekMap`

, we can now inspect our character stats and feed that *back* into our actions. This is *so* neat: any time you want to update one piece of data depending on another, `sneakyPeekMap`

is **exactly** what you need. Oh, and by the way, it has a much more common name: `extend`

!

*So, can I just think of extend as sneakyPeekMap?* I mean, you basically can; that intuition will get you a

**long**way. As an homage to Hardy Jones’ functional pearl, let’s build a

**Rose Tree**:

```
//- A root and a list of children!
//+ type RoseTree a = (a, [RoseTree a])
const RoseTree = daggy.tagged(
'root', 'forest'
)
```

*Maybe*, you looked at that type and a little voice in the back of your mind said `Functor`

. If so, **kudos**:

```
RoseTree.prototype.map = function (f) {
return RoseTree(
f(this.root), // Transform the root...
this.forest.map( // and other trees.
rt => rt.map(f)))
}
```

**No problem**; transform the root node, and then *recursively* map over all the child trees. **Bam**. *Now*, imagine if we wanted to *colour* this tree’s nodes depending on how many **children** they each have. Sounds like we’d need to take… a **sneaky peek**!

```
//+ extend :: RoseTree a
//+ ~> (RoseTree a -> b)
//+ -> RoseTree b
RoseTree.prototype.extend =
function (f) {
return RoseTree(
f(this),
this.forest.map(rt =>
rt.extend(f))
)
}
// Now, it's super easy to do this!
MyTree.extend(({ root, forest }) =>
forest.length < 1
? { ... root, colour: 'RED' }
: forest.length < 5
? { ... root, colour: 'ORANGE' }
: { ... root, colour: 'GREEN' })
```

With our new-found **superpower**, each node gets to pretend to be the **one in charge**, and can watch over their own forests. The trees in those forests then do the same, and so on, until we `map`

-with-a-sneaky-peek **the entire forest**! Again, I linked to Hardy’s article above, which contains a much **deeper** dive into trees specifically; combining `RoseTree`

with Hardy’s ideas is enough to make your own **billion-dollar React clone**!

Let’s cast our minds *waaay* back to the Setoid post, when we looked at `List`

. List, it turns out, is a `Functor`

:

```
//- Usually, if you can write something for
//- Array, you can write it for List!
List.prototype.map = function (f) {
return this.cata({
// Do nothing, we're done!
Nil: () => Nil,
// Transform head, recurse on tail
Cons: (head, tail) =>
Cons(f(head), tail.map(f))
})
}
// e.g. Cons(1, Cons(2, Nil))
// .map(x => x + 1)
// === Cons(2, Cons(3, Nil))
```

Now, for this **convoluted example**, let’s imagine we have some weather data for the last few days:

```
const arrayToList = xs => {
if (!xs.length) return Nil
const [ head, ... tail ] = this
return Cons(head, arrayToList(tail))
}
List.prototype.toArray = function () {
return this.cata({
Cons: (head, tail) => ([
head, ... tail.toArray()
]),
Nil: () => []
})
}
// Starting from today... (in celsius!)
const temperatures = arrayToList(
[23, 19, 19, 18, 18, 20, 24])
```

What we want to do is `map`

over this list to determine whether the temperature has been warmer or cooler than the day before! To do that, we’ll probably need to do *something* sneakily… any ideas?

```
//+ List a ~> (List a -> b) -> List b
List.prototype.extend = function (f) {
return this.cata({
// Extend the list, repeat on tail.
Cons: (head, tail) => Cons(
f(this), tail.extend(f)
),
Nil: () => Nil // We're done!
})
}
// [YAY, YAY, YAY, YAY, BOO, BOO, ???]
temperatures
.extend(({ head, tail }) =>
tail.length == 0 ? '???'
: head < tail.head
? 'BOO' : 'YAY')
.toArray()
```

We only used the *head* of the tail this time, but we could use the whole thing if we wanted! We have the entire thing available to peek sneakily.

For example, we could use this technique for lap times to record whether they’re

faster or slowerthan theaverageso far!Have a go!

As we said, we can mimic the same behaviour for `Array`

to save us all the to-and-fro with `List`

:

```
Array.prototype.extend = function (f) {
if (this.length === 0) return []
const [ _, ... tail ] = this
return [ f(this), ... tail.extend(f) ]
}
// Now, we can use array-destructuring :)
;[23, 19, 19, 18, 18, 20, 24].extend(
([head, ... tail]) =>
tail.length == 0
? '???'
: head < tail[0]
? 'BOO' : 'YAY')
```

I brought these examples up for a reason, Fantasists. *Often*, `extend`

isn’t just `f => W.of(f(this))`

for some `W`

type; that’s what `of`

is for! `extend`

is about being able to `map`

while being aware of the surrounding **construct**.

Think of it like this: when we used `Chain`

, we had total **write** access to the **output** *constructor* and *values*. We could turn `Just`

into `Nothing`

, we could fail a `Task`

, and we could even change the length of an `Array`

. **Truly, we were powerful**.

With `Extend`

, we get full **read** access to the **input** *constructor* and *values*. It’s the **opposite idea**.

Whereas `Chain`

lets us **inform the future** of the computation, `Extend`

lets us **be informed by the past**. *This is the kind of sentence that ends up on a mug, you know!*

```
-- chain: `map` with write-access to output
-- extend: `map` with read-access to input
map :: f a -> ( a -> b) -> f b
chain :: m a -> ( a -> m b) -> m b
extend :: w a -> (w a -> b) -> w b
```

There are lots of cool examples of `Extend`

, but they are often overlooked and generally considered a more “advanced” topic. After all, with `Monad`

, we’re free to build **anything**; why bother continuing? Well, I hope this gives you an idea of how they work and where you can find them! After all, these are all just **design patterns**: just use them when they’re **appropriate**!

*So, Semigroup is to Monoid as Chain is to Monad as Extend is to…?* We’ll find out next time! Before we go, though, here’s a very tricky challenge to keep you busy:

With

`Writer`

, we needed a`Semigroup`

on the left to make a`Chain`

instance, but we didn’t for`Extend`

.`Reader`

has an`Extend`

instance; can you think of how we might write that?

Until then, take a look through this article’s code, and take care!

♥