Pipe is straightforward. Whatever you pass into it, gets passed into the first function in your list. And then the result just makes it's way down the functions. The same way pipe works on the command line.

Oh and compose? It's the same as pipe, with one difference. Instead of starting at the top of your list of functions, it starts at the bottom and works its way up.

Immutability

At some point in your research on functional programming, immutability will come up. If something is immutable, then you can't change it or you get an error.

Oh how unfortunate that is. I'm sure this is due to some desire for performance, but it limits the utility of the const keyword. I would have much preferred to have const be recursively immutable on Objects and Arrays.

And it used on various screens. But then a coder decides that they don't need age. So they mutate the array, by setting it to user objects without ages.

Now everything that relies on age breaks. And there will be all sorts of weird bugs and display issues.

It seems like this wouldn't be that terrible to track down. But in a large application, with lots of shared global state, it is a nightmare.

In fact, my recommendation for many applications like this is simple: rewrite it.

And if you're into event-based programming, that can get complicated too. If you have events that fetch data and set it in the state and then those events kick of other events that kick off other events... If all along that path, everyone's mutating state as they go, expect enormous pain.

But if everything is immutable, problem solved. You can't change a reference once it is set. And if you want to change your state then you have to give it a completely new copy of the state.

There's a cost to be sure. But you can turn it off in production if you're concerned about performance. You'll still get the benefits of having some guard rails up during development that can guide you.

Pattern Matching

You don't get this in Javascript yet, but there's a proposal in stage 0.

Pattern matching is a better and more reliable way to write if and else-if statements.

Okay so there's not much difference here. The Javascript version is a little more wordy and 5 lines instead of 3.

The real difference is in the Haskell compiler. Haskell pattern-matching requires you to handle all possible cases in your pattern matches. In this case, we do, because we handle all positive numbers, all negative numbers and 0.

What if we didn't handle all cases? If we missed handling 0 or something. The Haskell compiler would throw an error. This is great because it forces you to handle a lot of edge cases that you could miss.

In Javascript, you're on your own to make sure you're thinking about the edge cases.

In Ramda there is the cond function which will give you some small satisfaction:

There's power in the notion that you could define such a simple Boolean type. And you could use this type like any other language provided bool type. But with nothing special built into the compiler, to make it work.

Another revelation I had in my readings. Say we are using Flow in ES6:

type EmailType = string;
const email: EmailType = 'yolo@foreal.com';

Hmmm, that's strange. Why would we do that? Does it achieve anything?

You still have a string in the end, so it may seem pointless. But let me tell you why this is useful.

If you never touched this email type then you would still benefit. It allows you to see every reference to this type in your code.

But is it realistic to expect that we will never change the email type? We could add functions that validate the email address. That function could use EmailType in its signature instead of string.

Or if we decided that we wanted EmailType to be an object, with an email address as well as inbox and sent properties. We could limit the length of an email address by passing it into a constructor.

And these refactorings would can succeed. Since we have this placeholder type to find and update all references.

The first one is better. It's much shorter for starters. Ramda curries everything, which is why you have to curry in the second one, to get that same benefit.

pathEq may look confusing, but once you know what it does, it's pretty simple to understand at a glance.

In the first example, there's not much to test. You don't have to test pathEq because Ramda presumably tests that. As long as you have an object with a valid path of name.last then that function will work.

The second example is trivial, but it is actual code that you may have gotten wrong. Depending on your tooling, it could be easy to miss something.

We now have a generic query function that you can apply to any array. We pass the functions into our query function. And nothing in our definition says anything about the employee type. So we could use this function to query other types in an array as well.