After Sliced Bread Came Ramda.js (Part I)

alt A ram

It Began in the Age of C#

This is Part I of a two part series on functional programming here's Part II

I used to be like everyone else. I thought I was going to own the world through imperative programming.

I envisioned class hierarchies to the ceiling that could run an entire business. Abstract classes, interfaces, inheritance, getters, setters, this and self.

Private properties, public properties and protected properties. Oh my! There is a lot of shit to keep track of in an object-oriented world.

But no one could tell me anything different at the time. I knew it all!

Then something strange started to happen. Things started showing up in C# that I hadn't used before.

Things like LINQ, with Select, Where, OrderBy and GroupBy. I took to this, like a duck to water.

You could also pass functions around as variables in C#, with Action and Func<T, ...>. Although, this didn't seem as revolutionary to me. After all you've been able to do this in Javascript pretty much forever.

I've been writing Javascript and taking this ability for granted since I was 17 years old.

But, C# was annoying because your functions had to have strongly-typed signatures. In Javascript, you could do anything you wanted.

Generics helped, in that they gave you more flexibility to express yourself. But it was also painful code to write.

If you got over the complex syntax, you were still left with the verbosity of an object-oriented world.

I started to learn about this whole new paradigm called functional programming. I remembered all the times in my career where I was unhappy with the implementation of some code.

And I often found myself asking, "Why can't this class be a simple function? Why do I need all this dependency injection? Why can't I pass the dependencies into my function, as other functions?"

Turns out you can.

It started to dawn on me that imperative programming may not be the end all be all. Functional programming seemed like it may be closer to my natural tendencies.

While C# is a pleasant and fine language, I still felt restricted. I switched jobs and started to ditch C# in favor of working more with Javascript.

Javascript Code Monkey

Not everyone thought that this was a smart decision back in 2012-2013. Some people laughed, and others would still laugh today.

But there is no shortage of work in JS and it is exploding to become the most dominant language on the planet. For better or worse.

So, I did what anyone would do. I started returning functions from my functions.

I thought it was nifty that you could configure the state for a function in the first call:

You'll have to forgive me, in this example I want to show the code as it was before ES6

function getIncrementor() {  
  var ctr = 0;
  return function incrementor() {
    ctr++;
    return ctr;
  };
}

var inc = getIncrementor(); // function incrementor  
inc(); // 1  
inc(); // 2  
inc(); // 3  

The enclosed state in the function acted as private data. Yet it remembered the ctr between function calls. At the time this was super handy! Anything that made Javascript seem more object-oriented was a win for me. And this was like private properties in classes.

I also realized that the LINQ methods I loved, were functional constructs of a different name. Select was map and Where was filter. I would later discover many more, including reduce, flatMap, curry and compose. The well was much deeper than I thought.

The Age of Lodash

The next stepping stone in my journey was underscore/lodash. All maps and filters and finds flowed through there for a long time. And let me tell you, I felt pretty slick.

Lodash was a big step. It got me thinking about programming in functions. Things like pick and path, which are functions for accessing data on an object.

That's not something I would have used a function for in the past. Like everyone else I would say person.name instead of _.pick(person, ['name']).

Imperative programmers look at those two options and say, "But person.name is so much simpler! Why on Earth would you ever want to do the second one?"

Well..we will get into this later, but for now think of it like this. In a world, where everything is a function, accessing .name is not a function. It's hard coding some data access.

To be sure, you could write a function like this:

const name = person => person.name; // Not bad, better than person.name

// But you could also do this
import R from 'ramda';  
const name = R.prop('name'); // We'll get into this later  

But this new paradigm of everything is a function started to invade my psyche.

I even started to wonder, "Is there a good use for the identity function?"

Before this, I thought the identity function was useless. It turns out that I was wrong. It's simple enough to call the identity function. But knowing why you would want to call it is another part of the journey.

I was looking through the code for underscore or lodash at one point, I don't remember which. Anyway, I remember something like this:

['Boolean', 'Number', 'String', 'Function'].forEach(type => {
  _['is' + type] = function is(value) {
    return type.toLowerCase() === typeof value;
  };
});

This is setting up the functions isBoolean, isNumber, isString and isFunction.
I remember looking at that and thinking, wow! What economy of words!

The rule is: Don't repeat yourself. But this was taking it one step further.

Here they didn't even repeat the assigment, as in _.isString = is('String'). Even the assignments of those functions to _ boiled down to a single statement.

Further proof, that I was into a different way of thinking about things.

The Age of Haskell

I haven't worked a ton with Haskell. It's kind of like when I was first trying to quit smoking. I've tried to learn Haskell 7 times and I still haven't quite gotten there.

To get there with Haskell is to understand functional programming in its entirety.

But I don't have that luxury. I work for a living and not on things that are this progressive.

What I learned from Haskell were bits and pieces about type theory. I learned that you could have a type system that was so intense, that it was near impossible to have a runtime error.

In theory, that appealed to me. But you have to understand that this is like holding a Javascript programmer at gunpoint.

ES6 (No More Shining Shoes Tommy)

Check out how sick ES6 is:

const pipe = (...functions) => startingValue =>  
  functions.reduce(
    (value, f) => f(value), 
    startingValue
  );

const toUpper = x => x.toUpperCase();  
const dropFirst = x => x.slice(1);  
pipe(toUpper, dropFirst)('hello'); // 'ELLO'

const inc = x => x + 1;  
const dec5 = x => x - 5;  
const times20 = x => x * 20;

pipe(inc, dec5, times20)(10); // 120  

Not a for-loop in sight! Today was a good day.

I'm sorry is this Javascript or some sort of OCaml shit? Nice right.

One of the things I forgot to mention in the Age of C# was my love of lambda functions. I loved the concise syntax so much that I wanted everything to be a lambda function. But alas, in the land of objects this was not meant to be.

When I started using ES5, I was super annoyed as I was going through lambda withdrawal.

You be the judge:

(x, y) => x + y

function (x, y) {  
  return x + y;
}

You don't get extra points for typing extra characters.

So ES6 came along and PSSHHHH MIND=BLOWN

It was like Christmas for nerds. It's like oh Javascript, humming along for 20 years, nothing to see here.

And then BOOM:

  • Arrow functions
  • let
  • const
  • Destructuring
  • Default Values
  • Rest/Spread Operator
  • Template Strings
  • Native Promises
  • Modules
  • Classes?!
  • Generators?!?!
  • Proxies?!?!?!

It was incredible! In ES5 the only option was the var keyword shudder. Now we had let and const all in one shot.

It wasn't perfect though. It annoyed me that const didn't make the entire object or array immutable. You can achieve this by recursively calling Object.freeze. But that would have been handy as part of the spec for const itself.

Performance be damned!

Destructuring and the rest/spread operator also allowed very concise syntax:

const list = [1, 2, 3, 4];  
const [x, ...xs] = list; // Woah what the hell is this, Haskell?

console.log(x); // 1  
console.log(xs); // [ 2, 3, 4 ]  
console.log(...xs); // 2, 3, 4  

Why didn't they include pattern matching in ES6? Ah well.

And my beloved arrow functions of course.

This is so important. If everything is a function, then it must not be painful to create functions. Arrow functions achieve that goal.

Stay tuned for Part II of this series on functional programming.

Next Time: The Cambrian Explosion (Ramda Arrives)

Screaming Goat

If you found this article to be helpful, then you should subscribe here.

Subscribe to our mailing list

* indicates required
Subscribe
X