Check out a free preview of the full Hardcore Functional Architecture Patterns in JavaScript course:
The "contramap" Lesson is part of the full, Hardcore Functional Architecture Patterns in JavaScript course featured in this preview video. Here's what you'd learn in this lesson:

Brian explains that contramap maps over inputs, combines two reducers that were previously contermapped demonstrating that contermap hits arguments before it comes in.

Get Unlimited Access Now

Transcript from the "contramap" Lesson

>> So contravariant functors are functors that operate on their first value. So if I have a function from a to string, right, and I know it will always return me a string. But I can take in any a to begin with. I can map over the a and turn it into a b but it will always end up on a string.

[00:00:22] SO an example of that, and we could do this with sort functions, predicate functions. Predicate functions take in anything and return a Bool, right, sorting functions return an enum of -1, 0, 1, or something. But we're able to map over to the argument, and this is kind of like a superpower, right?

[00:00:45] So if I start off with a function, let's do Reducer because that one's kinda fun. So this takes, I'll say run. And, what is Reducer holding? It's a taking an accumulator and an x or some a returning a new accumulator, right? So, accumulators fixed. I can't map over it, it can't change that.

[00:01:09] But it can change each of these values a to a b cuz it doesn't really matter, so that it sets like an input type that I can map over. So let's go ahead and model Reducers. And we have a run function exposed. And we have a concat. So let's just so how we can concat two Reducers.

[00:01:31] We could take a Reducer, I'm actually not gonna deliver that you can concat two Reducers just by merging the accumulators or picking one or the other. Let's do contramap. This is the thing we're focused on. So, contramap takes a function f. And instead of writing map where we would map over the output, we're gonna map over the input, does that look like.

[00:01:54] We're returning a new Reducer because we're mapping, we take our accumulator and our value. And we're gonna run our thing on the accumulator, and we're gonna hit that x before it ever gets there. So, what we've done is transformed the value before it got to our function. And we're able to do these contramaps.

[00:02:16] And that is useful if you have a bunch of functions you're gonna combine. So, I can make a few Reducers. We could write concat here real quick, but let's say we have Reducer like login. And another we're gonna concat that with a Reducer that's like change page or whatever.

[00:02:40] And the thing is if I wanna run this with just like a payload, just some kind of like, let's say this is like the action. It has a user and the user has a bunch of stuff and it's got like an environment and that's got a bunch of stuff.

[00:02:57] When I'm able to do is actually contramap each of these functions and actually pluck values off the payload. So we'll get the user here, And then we concat that with change page which should take us make this the router or the current page. Change page should will contramap the payload and taken the current page.

[00:03:32] All right so, we've done is combined two Reducers, both of them have been contramapped in advance to take this one input and transform it into what they're actually looking for as an input to their functions. And then, I'm running it with some state and some payload new, get all those and run it.

[00:03:53] So the point is, contramap hits arguments before it comes in. That's part of the exercises. So I wanted to call that out. Does anybody have any questions on how contramap works? Cool, this is going swimmingly, stuff is hard. [LAUGH] All right, so we have, yes?
>> So the purpose of contramap is to keep the entire payload going through this system, but plucking things off and passing it to inner functions?

>> That's a good question. That is one use case you can do, you can say like I'm combining a bunch of functions but they all take different inputs, right? And I'm gonna call run once after I've combined all my functions. So this is one use case I was using reducers to say like, hey, you have all these reducers that you've combined but they all take different inputs.

[00:04:39] Well we can contramap before they get there. So if you're combining functions into one, you might wanna manipulate stuff before they get there. And this provides it's almost like a before hook. Whereas map would be like an after hook. So that gives you the ability to kind of get in there and change the argument before it arrives.

[00:04:59] And that tends to really only be useful in situations where you're combining functions into one and they all take the same input. And it's also useful in situations where you have a fixed output and the fixed output is static, but the input is not, and you're able to pre-compose instead of post compose to be able to build out applications.