Functional-Light JavaScript, v3

Point Free Refactor

Kyle Simpson

Kyle Simpson

You Don't Know JS
Functional-Light JavaScript, v3

Check out a free preview of the full Functional-Light JavaScript, v3 course

The "Point Free Refactor" Lesson is part of the full, Functional-Light JavaScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Kyle walks through the process of defining a function in terms of another function and then converting it to a point-free function, and explains how this can increase code readability.


Transcript from the "Point Free Refactor" Lesson

>> Kyle Simpson: So what we wanna do is we wanna get to that idea of the shapes being equal with each other. Here I have an isOdd function. It's pretty straightforward. It uses the modular operator. So any value module 02, if it returns us one, that means it was an odd number, if it returns to 0, it was even number, okay?

Very basic math concept there. But if I wanted to find the isEven function, there's a couple of ways that I could have done it. I could have said isEven and on line 6, I could have said, v mod 2 == 0.
>> Kyle Simpson: And that would work just fine.

It's mathematically accurate to say that isEven is v mod 2 = 0. But I did it a little differently, I defined the isEven in terms of the isOdd function. And specifically, I negated it because we have a binary here, something is either even or odd, it's not not both and it's not neither, it's either a number is either even or it's not.

So, I'm asking the question here, if I take this isEven function and I define it in terms of isOdd. As opposed to doing just v mod 2 = 0. What have I purchased with that choice? What benefit am I getting from defining isEven in terms of isOdd? And the answer I would say is, I have created a more visible relationship between the two functions.

I have said that isEven is the negation of isOdd. Whereas if I just done v mod 2 = 0, that relationship would exist but it would be completely non obvious. Here I am attempting to make it more obvious, the relationship between isOdd and isEven by defining one in terms of the other.

So it's not just about saving keystrokes, a lot of times you hear people say well I [SOUND] dry, don't repeat yourself, right? That might be why a lot of people would justify dry, don't repeat yourself. I'm not saying that there isn't benefit there. Being unnecessarily repetitive can sometimes hamper the readability of a program.

But actually it turns out, sometimes in functional programming, it is better to be repetitive. So we don't want to take dry as like a religious artifact, like I have to have every certain thing written only once and everything is using the generic, whatever. That's not always the best.

Here, we're not doing, isEven in terms of isOdd because we want to save a few characters of the modulo operator. Because we wanna make it obvious that there's a relationship, a negation relationship between the two. And by thinking that way, we actually got ourselves 90% of the way to being able to answer this question which is, could I define the isEven function in a point freeway?

Could I define it in terms of isOdd without having to list out that v that's being passed in because there's the point. This is a pointed definition and we're asking, could I define it point free? Before I even show you how to do the point free, we probably should have motivated why, what is the point of point free, like what what are we buying there?

Well what we're doing is we're moving to that declarative style. When we have points, what we have is an imperative style that routes data from an input to an input. But when we use point free style, we have a declarative thing. Here's a strange phenomenon that I've seen with the idea between imperative and declarative.

Because the words themselves, the physical letters in those words, to me, imply that imperative would be implicit, since the words seem the same. But it turns out that it's reverse. It turns out that imperative code is generally more explicit and declarative code is generally more implicit. Now, you stop any, 100 software developers somewhere and you ask them the question is it better for a code to be explicit or implicit, 99 out of 100 are gonna tell you it's better to be explicit.

And what we're actually suggesting here is that in some senses, it's better to be implicit. It's better to be declarative and allow the existing Lego pieces that are in our application, either in the language or in our libraries to handle those unnecessary details. Because it's not important for the reader of this code to see v on line five being passed on line six.

That is an unnecessary detail. If I can define this in a point free array, I free up the reader to glance at and realize, okay, isEven is the negation of isOdd. So how are we gonna accomplish that? If you can agree with me that it is beneficial from a readability perspective, how are we gonna accomplish it?

We're gonna accomplish it by creating a utility that adapts the shape of a function, exactly like we did before with HOF. We're gonna make another HOF. Actually, we don't need to invent one, one already exists. I'm just going to tell you about it. Let's think about a HOF, a Higher Order Function called not.

This is by the way, often referred to as complement in functional programming libraries. I don't like that name, that confuses me. So I like to use not. Sometimes I use negate, sometimes I use not. I almost never use complement. But anyway, if you're looking it up, you'll find it, it's called complement in for something like.

But what it does is it takes the function fn, line 1, it makes a new function that's negated, line 2, and all it does is call the original underlying function with all the inputs and return the outputs. But it does line 3, that little exclamation mark, it negates it.

So now, when I declare isEven, I simply call this Higher Order Function utility not and I pass in isOdd. And what I would argue is not only is line 11 less to read and mentally juggle, cuz I don't need to see the function calling another function, passing the parameters, but it is even more clearer the relationship between isOdd and isEven now, right?

You can very clearly see that isOdd is the negation, that isEven is the negation of isOdd, that's where we get the readability gains in functional programming and specifically in point freestyle. You define one function in terms of another, you make the relationship between them much more clear. You allow the how, the imperative details to be implicitly hidden through a declarative style of coding.

>> Kyle Simpson: That's the big takeaway from all the functional programming, you could almost stop, right here at the and just get that and you've gotten a huge nugget of wisdom out of functional programming. That's the key idea.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now