# Fantas, Eel, and Specification 18: Bifunctor and Profunctor

The worst is behind us. We’ve mastered the `Monad`, conquered the `Comonad`, and surmounted the `Semigroup`. Consider these last two posts to be a cool-down, because the end is in sight. Today, to enjoy our first week of rest, we’re going to revise functors. A number of times, we’ve seen types with two inner types: `Either`, `Pair`, `Task`, `Function`, and so on. However, in all cases, we’ve only been able to `map` over the right-hand side. Well, Fantasists, the reason has something to do with a concept called kinds that we won’t go into. Instead, let’s look at solutions.

We’ll take a type like `Either` or `Pair`. These types have two inner types (left and right!) that we could `map` over. The `Bifunctor` class allows us to deal with both:

``````bimap :: Bifunctor f
=> f a c
~> (a -> b, c -> d)
-> f b d
``````

It’s pretty much exactly like `Functor`, except we are mapping two at a time! What does this look like in actual code?

``````Either.prototype.bimap =
function (f, g) {
return this.cata({
Left: f,
Right: g
})
}

Pair.prototype.bimap =
function (f, g) {
return Pair(f(this._1),
g(this._2))
}

function (f, g) {
this.fork(e => rej(f(e)),
x => res(g(e))))
}
``````

Hopefully, no huge surprises. We apply the left function to any mention of the left value, and the same for the right. Even the laws are just doubled-up versions of the `Functor` laws:

``````// For some functor U:

// Identity
U.map(x => x) === U

// Composition
U.map(f).map(g) ===
U.map(x => g(f(x)))

// For some bifunctor C:

// Identity
C.bimap(x => x, x => x) === C

// Composition
C.bimap(f, g).bimap(h, i) ===
C.bimap(l => h(f(l)),
r => i(g(r)))
``````

A lot of brackets, but look closely: the laws are the same, but we have two independent “channels” on the go!

Fun fact: if you have a `Bifunctor` instance for some type `T`, you can automatically derive a fully-lawful `Functor` instance for `T a` with `f => bimap(x => x, f)`. Hooray, Free upgrades!

So, is this useful? Yes! Let’s look at a neat little example using `Either` for a second:

``````//- Where everything changes...
isValid(user) ? Right(user)
: Left('Boo')

//- Function map === "piping".
//+ failureStream :: String
//+               -> HTML
const failureStream =
(x => x.toUpperCase())
.map(x => x + '!')
.map(x => '<em>' + x + '</em>')

//+ successStream :: User
//+               -> HTML
const successStream =
(x => x.name)
.map(x => 'Hey, ' + x + '!')
.map(x => '<h1>' + x + '</h1>')

//- We can now pass in our two
//- possible application flows
//- using `bimap`!
failureStream,
successStream)
``````

Note that this would also work with `Task`! We’re in a situation where we want to transform a potential success or failure, and `bimap` lets us supply both at once. Cool, right? Straightforward, too!

Now, `Function` is a slightly different story. Effectively, we can `contramap` over its left-hand type (the input) and `map` over its right-hand type (the output). It turns out there’s a fancy name for this sort of thing, too: `Profunctor`.

``````promap :: Profunctor p
=> p b c
~> (a -> b, c -> d)
-> p a d
``````

You can think of it as adding a before and after step to some process. Naturally, the laws look like a mooshmash of `Contravariant` and `Functor`:

``````// For some profunctor p:

// Identity...
P.promap(a => a, b => b) === P

// Composition...
p.promap(f, i).promap(g, h) ===
p.promap(a => f(g(a)),
b => h(i(b)))
``````

Guess what? You can build a functor `P a` out of any profunctor `P`: `f => promap(x => x, f)` is all it takes. So many free upgrades!

The left-hand side looks like `Contravariant`, and the right-hand side like `Functor`. Of course, we’ve seen a `Profunctor` already: `Function`! However, to give a slightly more exciting example, let’s look at one of my favourites: `Costar`.

``````//- Fancy wrapping around a specific type
//- of function: an "f a" to a "b"
//+ Costar f a b = f a -> b
const Costar = daggy.tagged('Costar', ['run'])

//- Contramap with the "before" function,
//- fold, then apply the "after" function.
//+ promap :: Functor f
//+        => Costar f b c
//+        -> (b -> a, c -> d)
//+        -> Costar f a d
Costar.prototype.promap = function (f, g) {
return Costar(x => g(this.run(x.map(f))))
}

//- Takes a list of ints to the sum
//+ sum :: Costar Array Int Int
const sum = Costar(xs =>
xs.reduce((x, y) => x + y, 0))

//- Make every element 1, then sum them!
const length = sum.promap(_ => 1, x => x)

//- Is the result over 5?
const isOk = sum.promap(x => x, x => x > 5)

//- Why not both? Is the length over 5?
const longEnough = sum.promap(
_ => 1, x => x > 5)

// Returns false!
longEnough.run([1, 3, 5, 7])
``````

`Costar` allows us to take the idea of `reduce` and wrap it in a `Profunctor`. We can use `promap` to prepare different inputs for the reduction and manipulate the result. You may have heard of this idea before: map/reduce. No matter how complex the process, there’s a good chance that you can express it in a `Profunctor`!

These are, of course, very quick overviews of `Bifunctor` and `Profunctor`. That said, if you’re comfortable now with `Functor` and you remember the post on `Contravariant`, there’s nothing new to learn! We’re really just building on ideas we’ve already had. `Bifunctor` might seem a little underwhelming now that we’ve seen the power of `Monad` and `Comonad`, but it’s twice as powerful as `Functor`: we can define a flow for success and error, for left and right, for… well, any two things!

As for `Profunctor`, it’s a pretty massive topic once you start digging. `Costar` is the opposite of `Star`, which is an `a -> f b` function; why not think about how to implement that? Would you need any special conditions to make it a `Profunctor`?

Take the article’s gist, and `bimap` and `promap` until the cows come home, Fantasists, for there is only one article left: `Semigroupoid` and `Category`. Expect high drama, hard maths, and herds of monoids. Well, maybe not the second thing…

Until then!