- Learning to Drive
- Your First Spaceship
- Forget Everything You Know
- Purity
- Immutability
- Friendly Reminder
- Refactoring
- Higher-Order Functions
- Closures
- Function Composition
- Point-Free Notation
- Trouble in Paradise
- Currying
- Currying and Refactoring
- Common Functional Functions
- Referential Transparency
- Execution Order
- Type Annotations
- Now What?
- Functional Javascript
- Javascript Shortcomings
- Elm
- The Future
Taking that first step to understanding Functional Programming concepts is the most important and sometimes the most difficult step. But it doesn’t have to be. Not with the right perspective.
Learning to Drive
When we first learned to drive, we struggled. It sure looked easy when we saw other people doing it. But it turned out to be harder than we thought.
We practiced in our parent’s car and we really didn’t venture out on the highway until we had mastered the streets in our own neighborhood.
But through repeated practice and some panicky moments that our parents would like to forget, we learned to drive and we finally got our license.
With our license in hand, we’d take the car out any chance we could. With each trip, we got better and better and our confidence went up. Then came the day when we had to drive someone else’s car or our car finally gave up the ghost and we had to buy a new one.
What was it like that first time behind the wheel of a different car? Was it like the very first time behind the wheel? Not even close. The first time, it was all so foreign. We’ve been in a car before that, but only as a passenger. This time we were in the driver seat. The one with all the controls.
But when we drove our second car, we simply asked ourselves a few simple questions like, where does the key go, where are the lights, how do you use the turn signals and how do you adjust the side mirrors.
After that, it was pretty smooth sailing. But why was this time so easy compared to the first time?
That’s because the new car was pretty much like the old car. It had all the same basic things that a car needs and they were pretty much in the same place.
A few things were implemented differently and maybe it had a few additional features, but we didn’t use them the first time we drove or even the second. Eventually, we learned all the new features. At least the ones we cared about.
Well, learning programming languages is sort of like this. The first is the hardest. But once you have one under your belt, subsequent ones are easier.
When you first start a second language, you ask questions like, “How do I create a module? How do you search an array? What are the parameters of the substring function?”
You’re confident that you can learn to drive this new language because it reminds you of your old language with maybe a few new things to hopefully make your life easier.
Your First Spaceship
Whether you’ve been driving one car your whole life or dozens of cars, imagine that you’re about to get behind the wheel of a spaceship.
If you were going to fly a spaceship, you wouldn’t expect your driving ability on the road to help you much. You’d be starting over from square zero. (We are programmers after all. We count starting at zero.)
You would begin your training with the expectation that things are very different in space and that flying this contraption is very different than driving on the ground.
Physics hasn’t changed. Just the way you navigate within that same Universe.
And it’s the same with learning Functional Programming. You should expect that things will be very different. And that much of what you know about programming will not translate.
Programming is thinking and Functional Programming will teach you to think very differently. So much so, that you’ll probably never go back to the old way of thinking.
Forget Everything You Know
People love saying this phrase, but it’s sort of true. Learning functional programming is like starting from scratch. Not completely, but effectively. There are lots of similar concepts but it’s best if you just expect that you have to relearn everything.
With the right perspective you’ll have the right expectations and with the right expectations you won’t quit when things get hard.
There are all kinds of things that you’re used to doing as a programmer that you cannot do any more with Functional Programming.
Just like in your car, you used to backup to get out of the driveway. But in a spaceship, there is no reverse. Now you may think, “WHAT? NO REVERSE?! HOW THE HELL AM I SUPPOSED TO DRIVE WITHOUT REVERSE?!”
Well, it turns out that you don’t need reverse in a spaceship because of its ability to maneuver in three dimensional space. Once you understand this, you’ll never miss reverse again. In fact, someday, you’ll think back at how limiting the car really was.
Learning Functional Programming takes a while. So be patient.
So let’s exit the cold world of Imperative Programming and take a gentle dip into the hot springs of Functional Programming.
What follows in this multi-part article are Functional Programming Concepts that will help you before you dive into your first Functional Language. Or if you’ve already taken the plunge, this will help round out your understanding.
Please don’t rush. Take your time reading from this point forward and take the time to understand the coding examples. You may even want to stop reading after each section to let the ideas sink in. Then return later to finish.
The most important thing is that you understand.
Purity
When Functional Programmers talk of Purity, they are referring to Pure Functions.
Pure Functions are very simple functions. They only operate on their input parameters.
Here’s an example in Javascript of a Pure Function:
var z = 10;
function add(x, y) {
return x + y;
}
Notice that the add function does NOT touch the z variable. It doesn’t read from z and it doesn’t write to z. It only reads x and y, its inputs, and returns the result of adding them together.
That’s a pure function. If the add function did access z, it would no longer be pure.
Here’s another function to consider:
function justTen() {
return 10;
}
If the function, justTen, is pure, then it can only return a constant. Why?
Because we haven’t given it any inputs. And since, to be pure, it cannot access anything other than its own inputs, the only thing it can return is a constant.
Since pure functions that take no parameters do no work, they aren’t very useful. It would be better if justTen was defined as a constant.
Most useful Pure Functions must take at least one parameter.
Consider this function:
function addNoReturn(x, y) {
var z = x + y
}
Notice how this function doesn’t return anything. It adds x and y and puts it into a variable z but doesn’t return it.
It’s a pure function since it only deals with its inputs. It does add, but since it doesn’t return the results, it’s useless.
All useful Pure Functions must return something.
Let’s consider the first add function again:
function add(x, y) {
return x + y;
}
console.log(add(1, 2)); // prints 3
console.log(add(1, 2)); // still prints 3
console.log(add(1, 2)); // WILL ALWAYS print 3
Notice that add(1, 2) is always 3. Not a huge surprise but only because the function is pure. If the add function used some outside value, then you could never predict its behavior.
Pure Functions will always produce the same output given the same inputs.
Since Pure Functions cannot change any external variables, all of the following functions are impure:
writeFile(fileName);
updateDatabaseTable(sqlCmd);
sendAjaxRequest(ajaxRequest);
openSocket(ipAddress);
All of these function have what are called Side Effects. When you call them, they change files and database tables, send data to a server or call the OS to get a socket. They do more than just operate on their inputs and return outputs. Therefore, you can never predict what these functions will return.
Pure functions have no side effects.
In Imperative Programming Languages such as Javascript, Java, and C#, Side Effects are everywhere. This makes debugging very difficult because a variable can be changed anywhere in your program. So when you have a bug because a variable is changed to the wrong value at the wrong time, where do you look? Everywhere? That’s not good.
At this point, you’re probably thinking, “HOW THE HELL DO I DO ANYTHING WITH ONLY PURE FUNCTIONS?!”
In Functional Programming, you don’t just write Pure Functions.
Functional Languages cannot eliminate Side Effects, they can only confine them. Since programs have to interface to the real world, some parts of every program must be impure. The goal is to minimize the amount of impure code and segregate it from the rest of our program.
Immutability
Do you remember when you first saw the following bit of code:
var x = 1;
x = x + 1;
And whoever was teaching you told you to forget what you learned in math class? In math, x can never be equal to x + 1.
But in Imperative Programming, it means, take the current value of x add 1 to it and put that result back into x.
Well, in functional programming, x = x + 1 is illegal. So you have to remember what you forgot in math… Sort of.
There are no variables in Functional Programming.
Stored values are still called variables because of history but they are constants, i.e. once x takes on a value, it’s that value for life.
Don’t worry, x is usually a local variable so its life is usually short. But while it’s alive, it can never change.
Here’s an example of constant variables in Elm, a Pure Functional Programming Language for Web Development:
addOneToSum y z =
let
x = 1
in
x + y + z
If you’re not familiar with ML-Style syntax, let me explain. addOneToSum is a function that takes 2 parameters, y and z.
Inside the let block, x is bound to the value of 1, i.e. it’s equal to 1 for the rest of its life. Its life is over when the function exits or more accurately when the let block is evaluated.
Inside the in block, the calculation can include values defined in the let block, viz. x. The result of the calculation x + y + z is returned or more accurately, 1 + y + z is returned since x = 1.
Once again, I can hear you ask “HOW THE HELL AM I SUPPOSED TO DO ANYTHING WITHOUT VARIABLES?!”
Let’s think about when we want to modify variables. There are 2 general cases that come to mind: multi-valued changes (e.g. changing a single value of an object or record) and single-valued changes (e.g. loop counters).
Functional Programming deals with changes to values in a record by making a copy of the record with the values changed. It does this efficiently without having to copy all parts of the record by using data structures that makes this possible.
Functional programming solves the single-valued change in exactly the same way, by making a copy of it.
Oh, yes and by not having loops.
“WHAT NO VARIABLES AND NOW NO LOOPS?! I HATE YOU!!!”
Hold on. It’s not like we can’t do loops (no pun intended), it’s just that there are no specific loop constructs like for, while, do, repeat, etc.
Functional Programming uses recursion to do looping.
Here are two ways you can do loops in Javascript:
// simple loop construct
var acc = 0;
for (var i = 1; i <= 10; ++i)
acc += i;
console.log(acc); // prints 55
// without loop construct or variables (recursion)
function sumRange(start, end, acc) {
if (start > end)
return acc;
return sumRange(start + 1, end, acc + start)
}
console.log(sumRange(1, 10, 0)); // prints 55
Notice how recursion, the functional approach, accomplishes the same as the for loop by calling itself with a new start (start + 1) and a new accumulator (acc + start). It doesn’t modify the old values. Instead it uses new values calculated from the old.
Unfortunately, this is hard to see in Javascript even if you spend a little time studying it, for two reasons. One, the syntax of Javascript is noisy and two, you’re probably not used to thinking recursively.
In Elm, it’s easier to read and, therefore, understand:
sumRange start end acc =
if start > end then
acc
else
sumRange (start + 1) end (acc + start)
Here’s how it runs:
sumRange 1 10 0 = -- sumRange (1 + 1) 10 (0 + 1)
sumRange 2 10 1 = -- sumRange (2 + 1) 10 (1 + 2)
sumRange 3 10 3 = -- sumRange (3 + 1) 10 (3 + 3)
sumRange 4 10 6 = -- sumRange (4 + 1) 10 (6 + 4)
sumRange 5 10 10 = -- sumRange (5 + 1) 10 (10 + 5)
sumRange 6 10 15 = -- sumRange (6 + 1) 10 (15 + 6)
sumRange 7 10 21 = -- sumRange (7 + 1) 10 (21 + 7)
sumRange 8 10 28 = -- sumRange (8 + 1) 10 (28 + 8)
sumRange 9 10 36 = -- sumRange (9 + 1) 10 (36 + 9)
sumRange 10 10 45 = -- sumRange (10 + 1) 10 (45 + 10)
sumRange 11 10 55 = -- 11 > 10 => 55
55
You’re probably thinking that for loops are easier to understand. While that’s debatable and more likely an issue of familiarity, non-recursive loops require Mutability, which is bad.
I haven’t entirely explained the benefits of Immutability here but check out the Global Mutable State section in Why Programmers Need Limits to learn more.
One obvious benefit is that if you have access to a value in your program, you only have read access, which means that no one else can change that value. Even you. So no accidental mutations.
Also, if your program is multi-threaded, then no other thread can pull the rug out from under you. That value is constant and if another thread wants to change it, it’ll have create a new value from the old one.
Back in the mid 90s, I wrote a Game Engine for Creature Crunch and the biggest source of bugs was multithreading issues. I wish I knew about immutability back then. But back then I was more worried about the difference between a 2x or 4x speed CD-ROM drives on game performance.
Immutability creates simpler and safer code.
Taking that first step to understanding Functional Programming concepts is the most important and sometimes the most difficult step. But it doesn’t have to be. Not with the right perspective.
Previous parts: Part 1
Friendly Reminder
Please read through the code slowly. Make sure you understand it before moving on. Each section builds on top of the previous section.
If you rush, you may miss some nuance that will be important later.
Refactoring
Let’s think about refactoring for a minute. Here’s some Javascript code:
function validateSsn(ssn) {
if (/^\d{3}-\d{2}-\d{4}$/.exec(ssn))
console.log('Valid SSN');
else
console.log('Invalid SSN');
}
function validatePhone(phone) {
if (/^\(\d{3}\)\d{3}-\d{4}$/.exec(phone))
console.log('Valid Phone Number');
else
console.log('Invalid Phone Number');
}
We’ve all written code like this before and over time, we start to recognize that these two functions are practically the same and only differ by a few things (shown in bold).
Instead of copying validateSsn and pasting and editing to create validatePhone, we should create a single function and parameterize the things that we edited after pasting.
In this example, we would parameterize the value, the regular expressionand the message printed (at least the last part of the message printed).
The refactored code:
function validateValue(value, regex, type) {
if (regex.exec(value))
console.log('Invalid ' + type);
else
console.log('Valid ' + type);
}
The parameters ssn and phone in the old code are now represented by value.
The regular expressions /^\d{3}-\d{2}-\d{4}$/ and /^(\d{3})\d{3}-\d{4}$/ are represented by regex.
And finally, the last part of the message ‘SSN’ and ‘Phone Number’ are represented by type.
Having one function is much better than having two functions. Or worse three, four or ten functions. This keeps your code clean and maintainable.
For example, if there’s a bug, you only have to fix it in one place versus searching through your whole codebase to find where this function MAY have been pasted and modified.
But what happens when you have the following situation:
function validateAddress(address) {
if (parseAddress(address))
console.log('Valid Address');
else
console.log('Invalid Address');
}
function validateName(name) {
if (parseFullName(name))
console.log('Valid Name');
else
console.log('Invalid Name');
}
Here parseAddress and parseFullName are functions that take a string and return true if it parses.
How do we refactor this?
Well, we can use value for address and name, and type for ‘Address’ and‘Name’ like we did before but there’s a function where our regular expression used to be.
If only we could pass a function as a parameter…
Higher-Order Functions
Many languages do not support passing functions as parameters. Some do but they don’t make it easy.
In Functional Programming, a function is a first-class citizen of the language. In other words, a function is just another value.
Since functions are just values, we can pass them as parameters.
Even though Javascript is not a Pure Functional language, you can do some functional operations with it. So here’s the last two functions refactored into a single function by passing the parsing function as a parameter called parseFunc:
function validateValueWithFunc(value, parseFunc, type) {
if (parseFunc(value))
console.log('Invalid ' + type);
else
console.log('Valid ' + type);
}
Our new function is called a Higher-order Function.
Higher-order Functions either take functions as parameters, return functions or both.
Now we can call our higher-order function for the four previous functions (this works in Javascript because Regex.exec returns a truthy value when a match is found):
validateValueWithFunc('123-45-6789', /^\d{3}-\d{2}-\d{4}$/.exec, 'SSN');
validateValueWithFunc('(123)456-7890', /^\(\d{3}\)\d{3}-\d{4}$/.exec, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');
This is so much better than having four nearly identical functions.
But notice the regular expressions. They’re a bit verbose. Let’s clean up our a code by factoring them out:
var parseSsn = /^\d{3}-\d{2}-\d{4}$/.exec;
var parsePhone = /^\(\d{3}\)\d{3}-\d{4}$/.exec;
validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');
That’s better. Now when we want to parse a phone number, we don’t have to copy and paste the regular expression.
But imagine we have more regular expressions to parse, not just parseSsn and parsePhone. Each time we create a regular expression parser, we have to remember to add the .exec to the end. And trust me, this is easy to forget.
We can guard against this by creating a high-order function that returns the exec function:
function makeRegexParser(regex) {
return regex.exec;
}
var parseSsn = makeRegexParser(/^\d{3}-\d{2}-\d{4}$/);
var parsePhone = makeRegexParser(/^\(\d{3}\)\d{3}-\d{4}$/);
validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');
Here, makeRegexParser takes a regular expression and returns the execfunction, which takes a string. validateValueWithFunc will pass the string, value, to the parse function, i.e. exec.
parseSsn and parsePhone are effectively the same as before, the regular expression’s exec function.
Granted, this is a marginal improvement but is shown here to give an example of a high-order function that returns a function.
However, you can imagine the benefits of making this change if makeRegexParser was much more complex.
Here’s another example of a higher-order function that returns a function:
function makeAdder(constantValue) {
return function adder(value) {
return constantValue + value;
};
}
Here we have makeAdder that takes constantValue and returns adder, a function that will add that constant to any value it gets passed.
Here’s how it can be used:
var add10 = makeAdder(10);
console.log(add10(20)); // prints 30
console.log(add10(30)); // prints 40
console.log(add10(40)); // prints 50
We create a function, add10, by passing the constant 10 to makeAdder which returns a function that will add 10 to everything.
Notice that the function adder has access to constantValue even after makeAddr returns. That’s because constantValue was in its scope when adder was created.
This behavior is very important because without it, functions that return functions wouldn’t be very useful. So it’s important we understand how they work and what this behavior is called.
This behavior is called a Closure.
Closures
Here’s a contrived example of functions that use closures:
function grandParent(g1, g2) {
var g3 = 3;
return function parent(p1, p2) {
var p3 = 33;
return function child(c1, c2) {
var c3 = 333;
return g1 + g2 + g3 + p1 + p2 + p3 + c1 + c2 + c3;
};
};
}
In this example, child has access to its variables, the parent’s variables and the grandParent’s variables.
The parent has access to its variables and grandParent’s variables.
The grandParent only has access to its variables.
(See pyramid above for clarification.)
Here’s an example of its use:
var parentFunc = grandParent(1, 2); // returns parent()
var childFunc = parentFunc(11, 22); // returns child()
console.log(childFunc(111, 222)); // prints 738
// 1 + 2 + 3 + 11 + 22 + 33 + 111 + 222 + 333 == 738
Here, parentFunc keeps the parent’s scope alive since grandParent returns parent.
Similarly, childFunc keeps the child’s scope alive since parentFunc, which is just parent, returns child.
When a function is created, all of the variables in its scope at the time of creation are accessible to it for the lifetime of the function. A function exists as long as there still a reference to it. For example, child’s scope exists as long as childFunc still references it.
A closure is a function’s scope that’s kept alive by a reference to that function.
Note that in Javascript, closures are problematic since the variables are mutable, i.e. they can change values from the time they were closed over to the time the returned function is called.
Thankfully, variables in Functional Languages are Immutable eliminating this common source of bugs and confusion.
Taking that first step to understanding Functional Programming concepts is the most important and sometimes the most difficult step. But it doesn’t have to be. Not with the right perspective.
Previous parts: Part 1, Part 2
Function Composition
As programmers, we are lazy. We don’t want to build, test and deploy code that we’ve written over and over and over again.
We’re always trying to figure out ways of doing the work once and how we can reuse it to do something else.
Code reuse sounds great but is difficult to achieve. Make the code too specific and you can’t reuse it. Make it too general and it can be too difficult to use in the first place.
So what we need is a balance between the two, a way to make smaller, reusable pieces that we can use as building blocks to construct more complex functionality.
In Functional Programming, functions are our building blocks. We write them to do very specific tasks and then we put them together like Lego™ blocks.
This is called Function Composition.
So how does it work? Let’s start with two Javascript functions:
var add10 = function(value) {
return value + 10;
};
var mult5 = function(value) {
return value * 5;
};
This is too verbose so let’s rewrite it using fat arrow notation:
var add10 = value => value + 10;
var mult5 = value => value * 5;
That’s better. Now let’s imagine that we also want to have a function that takes a value and adds 10 to it and then multiplies the result by 5. We couldwrite:
var mult5AfterAdd10 = value => 5 * (value + 10)
Even though this is a very simple example, we still don’t want to have to write this function from scratch. First, we could make a mistake like forget the parentheses.
Second, we already have a function that adds 10 and another that multiplies by 5. We’re writing code that we’ve already written.
So instead, let’s use add10 and mult5 to build our new function:
var mult5AfterAdd10 = value => mult5(add10(value));
We just used existing functions to create mult5AfterAdd10, but there’s a better way.
In math, f ∘ g is functional composition and is read “f composed with g” or, more commonly, “f after g”. So (f ∘ g)(x) is equivalent to calling f after calling g with x or simply, f(g(x)).
In our example, we have mult5 ∘ add10 or “mult5 after add10”, hence the name of our function, mult5AfterAdd10.
And that’s exactly what we did. We called mult5 after we called add10 with value or simply, mult5(add10(value)).
Since Javascript doesn’t do Function Composition natively, let’s look at Elm:
add10 value =
value + 10
mult5 value =
value * 5
mult5AfterAdd10 value =
(mult5 << add10) value
The << infixed operator is how you compose functions in Elm. It gives us a visual sense of how the data is flowing. First, value is passed to add10 then its results are passed to mult5.
Note the parentheses in mult5AfterAdd10, i.e. (mult5 << add10). They are there to make sure that the functions are composed first before applying value.
You can compose as many functions as you like this way:
f x =
(g << h << s << r << t) x
Here x is passed to function t whose result is passed to r whose result is passed to s and so on. If you did something similar in Javascript it would look like g(h(s(r(t(x))))), a parenthetical nightmare
Point-Free Notation
There is a style of writing functions without having to specify the parameters called Point-Free Notation. At first, this style will seem odd but as you continue, you’ll grow to appreciate the brevity.
In mult5AfterAdd10, you’ll notice that value is specified twice. Once in the parameter list and once when it’s used.
-- This is a function that expects 1 parameter
mult5AfterAdd10 value =
(mult5 << add10) value
But this parameter is unnecessary since add10, the rightmost function in the composition, expects the same parameter. The following point-free version is equivalent:
-- This is also a function that expects 1 parameter
mult5AfterAdd10 =
(mult5 << add10)
There are many benefits from using the point-free version.
First, we don’t have to specify redundant parameters. And since we don’t have to specify them, we don’t have to think up names for all of them.
Second, it’s easier to read and reason about since it’s less verbose. This example is simple, but imagine a function that took more parameters.
Trouble in Paradise
So far we’ve seen how Function Composition works and how we should specify our functions in Point-Free Notation for brevity, clarity and flexibility.
Now, let’s try to use these ideas in a slightly different scenario and see how they fare. Imagine we replace add10 with add:
add x y =
x + y
mult5 value =
value * 5
How do we write mult5After10 with just these 2 functions?
Think about it for a bit before reading on. No seriously. Think about. Try and do it.
Okay, so if you actually spent time thinking about it, you may have come up with a solution like:
-- This is wrong !!!!
mult5AfterAdd10 =
(mult5 << add) 10
But this wouldn’t work. Why? Because add takes 2 parameters.
If this isn’t obvious in Elm, try to write this in Javascript:
var mult5AfterAdd10 = mult5(add(10)); // this doesn't work
This code is wrong but why?
Because the add function is only getting 1 of its 2 parameters here then its incorrect results are passed to mult5. This will produce the wrong results.
In fact, in Elm, the compiler won’t even let you write such mis-formed code (which is one of the great things about Elm).
Let’s try again:
var mult5AfterAdd10 = y => mult5(add(10, y)); // not point-free
This isn’t point-free but I could probably live with this. But now I’m no longer just combining functions. I’m writing a new function. Also, if this gets more complicated, e.g. if I want to compose mult5AfterAdd10 with something else, I’m going to get into real trouble.
So it would appear that Function Composition has limited usefulness since we cannot marry these two functions. That’s too bad since it’s so powerful.
How could we solve this? What would we need to make this problem go away?
Well, what would be really great is if we had some way of giving our addfunction only one of its parameters ahead of time and then it would get its second parameter later when mult5AfterAdd10 is called.
Turns out there is way and it’s called Currying.
Taking that first step to understanding Functional Programming concepts is the most important and sometimes the most difficult step. But it doesn’t have to be. Not with the right perspective.
Previous parts: Part 1, Part 2, Part 3
Currying
If you remember from Part 3, the reason that we were having problems composing mult5 and add (in ) is because mult5 takes 1 parameter and addtakes 2.
We can solve this easily by just restricting all functions to take only 1 parameter.
Trust me. It’s not as bad as it sounds.
We simply write an add function that uses 2 parameters but only takes 1 parameter at a time. Curried functions allow us to do this.
A Curried Function is a function that only takes a single parameter at a time.
This will let us give add its first parameter before we compose it with mult5. Then when mult5AfterAdd10 is called, add will get its second parameter.
In Javascript, we can accomplish this by rewriting add:
var add = x => y => x + y
This version of add is a function that takes one parameter now and then another one later.
In detail, the add function takes a single parameter, x, and returns a functionthat takes a single parameter, y, which will ultimately return the result of adding x and y.
Now we can use this version of add to build a working version of mult5AfterAdd10:
var compose = (f, g) => x => f(g(x));
var mult5AfterAdd10 = compose(mult5, add(10));
The compose function takes 2 parameters, f and g. Then it returns a function that takes 1 parameter, x, which when called will apply f after g to x.
So what did we do exactly? Well, we converted our plain old add function into a curried version. This made add more flexible since the first parameter, 10, can be passed to it up front and the final parameter will be passed when mult5AfterAdd10 is called.
At this point, you may be wondering how to rewrite the add function in Elm. Turns out, you don’t have to. In Elm and other Functional Languages, all functions are curried automatically.
So the add function looks the same:
add x y =
x + y
This is how mult5AfterAdd10 should have been written back in Part 3:
mult5AfterAdd10 =
(mult5 << add 10)
Syntactically speaking, Elm beats Imperative Languages like Javascript because it’s been optimized for Functional things like currying and composition.
Currying and Refactoring
Another time currying shines is during refactoring when you create a generalized version of a function with lots of parameters and then use it to create specialized versions with fewer parameters.
For example, when we have the following functions that put brackets and double brackets around strings:
bracket str =
"{" ++ str ++ "}"
doubleBracket str =
"{{" ++ str ++ "}}"
Here’s how we’d use it:
bracketedJoe =
bracket "Joe"
doubleBracketedJoe =
doubleBracket "Joe"
We can generalize bracket and doubleBracket:
generalBracket prefix str suffix =
prefix ++ str ++ suffix
But now every time we use generalBracket we have to pass in the brackets:
bracketedJoe =
generalBracket "{" "Joe" "}"
doubleBracketedJoe =
generalBracket "{{" "Joe" "}}"
What we really want is the best of both worlds.
If we reorder the parameters of generalBracket, we can create bracket and doubleBracket by leveraging the fact that functions are curried:
generalBracket prefix suffix str =
prefix ++ str ++ suffix
bracket =
generalBracket "{" "}"
doubleBracket =
generalBracket "{{" "}}"
Notice that by putting the parameters that were most likely to be static first, i.e. prefix and suffix, and putting the parameters that were most likely to change last, i.e. str, we can easily create specialized versions of generalBracket.
Parameter order is important to fully leverage currying.
Also, notice that bracket and doubleBracket are written in point-free notation, i.e. the str parameter is implied. Both bracket and doubleBracketare functions waiting for their final parameter.
Now we can use it just like before:
bracketedJoe =
bracket "Joe"
doubleBracketedJoe =
doubleBracket "Joe"
But this time we’re using a generalized curried function, generalBracket.
Common Functional Functions
Let’s look at 3 common functions that are used in Functional Languages.
But first, let’s look at the following Javascript code:
for (var i = 0; i < something.length; ++i) {
// do stuff
}
There’s one major thing wrong with this code. It’s not a bug. The problem is that this code is boilerplate code, i.e. code that is written over and over again.
If you code in Imperative Languages like Java, C#, Javascript, PHP, Python, etc., you’ll find yourself writing this boilerplate code more than any other.
That’s what’s wrong with it.
So let’s kill it. Let’s put it in a function (or a couple of functions) and never write a for-loop again. Well, almost never; at least until we move to a Functional Language.
Let’s start with modifying an array called things:
var things = [1, 2, 3, 4];
for (var i = 0; i < things.length; ++i) {
things[i] = things[i] * 10; // MUTATION ALERT !!!!
}
console.log(things); // [10, 20, 30, 40]
UGH!! Mutability!
Let’s try that again. This time we won’t mutate things:
var things = [1, 2, 3, 4];
var newThings = [];
for (var i = 0; i < things.length; ++i) {
newThings[i] = things[i] * 10;
}
console.log(newThings); // [10, 20, 30, 40]
Okay, so we didn’t mutate things but technically we mutated newThings. For now, we’re going to overlook this. We are in Javascript after all. Once we move to a Functional Language, we won’t be able to mutate.
The point here is to understand how these functions work and help us to reduce noise in our code.
Let’s take this code and put it in a function. We’re going to call our first common function map since it maps each value in the old array to new values in the new array:
var map = (f, array) => {
var newArray = [];
for (var i = 0; i < array.length; ++i) {
newArray[i] = f(array[i]);
}
return newArray;
};
Notice the function, f, is passed in so that our map function can do anything we want to each item of the array.
Now we can call rewrite our previous code to use map:
var things = [1, 2, 3, 4];
var newThings = map(v => v * 10, things);
Look ma. No for-loops. And much easier to read and therefore reason about.
Well, technically, there are for-loops in the map function. But at least we don’t have to write that boilerplate code anymore.
Now let’s write another common function to filter things from an array:
var filter = (pred, array) => {
var newArray = [];
for (var i = 0; i < array.length; ++i) {
if (pred(array[i]))
newArray[newArray.length] = array[i];
}
return newArray;
};
Notice how the predicate function, pred, returns TRUE if we keep the item or FALSE if we toss it.
Here’s how to use filter to filter odd numbers:
var isOdd = x => x % 2 !== 0;
var numbers = [1, 2, 3, 4, 5];
var oddNumbers = filter(isOdd, numbers);
console.log(oddNumbers); // [1, 3, 5]
Using our new filter function is so much simpler than hand-coding it with a for-loop.
The final common function is called reduce. Typically, it’s used to take a list and reduce it to a single value but it can actually do so much more.
This function is usually called fold in Functional Languages.
var reduce = (f, start, array) => {
var acc = start;
for (var i = 0; i < array.length; ++i)
acc = f(array[i], acc); // f() takes 2 parameters
return acc;
});
The reduce function takes a reduction function, f, an initial start value and an array.
Notice that the reduction function, f, takes 2 parameters, the current item of the array, and the accumulator, acc. It will use these parameters to produce a new accumulator each iteration. The accumulator from the final iteration is returned.
An example will help us understand how it works:
var add = (x, y) => x + y;
var values = [1, 2, 3, 4, 5];
var sumOfValues = reduce(add, 0, values);
console.log(sumOfValues); // 15
Notice that the add function takes 2 parameters and adds them. Our reducefunction expects a function that takes 2 parameters so they work well together.
We start with a start value of zero and pass in our array, values, to be summed. Inside the reduce function, the sum is accumulated as it iterates over values. The final accumulated value is returned as sumOfValues.
Each of these functions, map, filter and reduce let us do common manipulation operations on arrays without having to write boilerplate for-loops.
But in Functional Languages, they are even more useful since there are no loop constructs just recursion. Iteration functions aren’t just extremely helpful. They’re necessary.
Taking that first step to understanding Functional Programming concepts is the most important and sometimes the most difficult step. But it doesn’t have to be. Not with the right perspective.
Previous parts: Part 1, Part 2, Part 3, Part 4
Referential Transparency
Referential Transparency is a fancy term to describe that a pure function can safely be replaced by its expression. An example will help illustrate this.
In Algebra when you had the following formula:
y = x + 10
And were told:
x = 3
You could substituted x back into the equation to get:
y = 3 + 10
Notice that the equation is still valid. We can do the same kind of substitution with pure functions.
Here’s a function in Elm that puts single quotes around the supplied string:
quote str =
"'" ++ str ++ "'"
And here’s some code that uses it:
findError key =
"Unable to find " ++ (quote key)
Here findError builds an error message when a search for key is unsuccessful.
Since the quote function is pure, we can simply replace the function call in findError with the body of the quote function (which is just an expression):
findError key =
"Unable to find " ++ ("'" ++ str ++ "'")
This is what I call Reverse Refactoring (which makes more sense to me), a process that can be used by programmers or programs (e.g. compilers and test programs) to reason about code.
This can be especially helpful when reasoning about recursive functions.
Execution Order
Most programs are single-threaded, i.e. one and only one piece of code is being executed at a time. Even if you have a multithreaded program, most of the threads are blocked waiting for I/O to complete, e.g. file, network, etc.
This is one reason why we naturally think in terms of ordered steps when we write code:
1. Get out the bread
2. Put 2 slices into the toaster
3. Select darkness
4. Push down the lever
5. Wait for toast to pop up
6. Remove toast
7. Get out the butter
8. Get a butter knife
9. Butter toast
In this example, there are two independent operations: getting butter and toasting bread. They only become interdependent at step 9.
We could do steps 7 and 8 concurrently with steps 1 through 6 since they are independent from one another.
But the minute we do this, things get complicated:
Thread 1
--------
1. Get out the bread
2. Put 2 slices into the toaster
3. Select darkness
4. Push down the lever
5. Wait for toast to pop up
6. Remove toast
Thread 2
--------
1. Get out the butter
2. Get a butter knife
3. Wait for Thread 1 to complete
4. Butter toast
What happens to Thread 2 if Thread 1 fails? What is the mechanism to coordinate both threads? Who owns the toast: Thread 1, Thread 2 or both?
It’s easier to not think about these complexities and leave our program single threaded.
But when it’s worth squeezing out every possible efficiency of our program, then we must take on the monumental effort to write multithreading software.
However, there are 2 main problems with multithreading. First, multithreaded programs are difficult to write, read, reason about, test and debug.
Second, some languages, e.g. Javascript, don’t support multithreading and those that do, support it badly.
But what if order didn’t matter and everything was executed in parallel?
While this sounds crazy, it’s not as chaotic as it sounds. Let’s look at some Elm code to illustrate this:
buildMessage message value =
let
upperMessage =
String.toUpper message
quotedValue =
"'" ++ value ++ "'"
in
upperMessage ++ ": " ++ quotedValue
Here buildMessage takes message and value then produces an uppercased message, a colon and value in single quotes.
Notice how upperMessage and quotedValue are independent. How do we know this?
There are 2 things that must be true for independence. First, they must be pure functions. This is important because they must not be affected by the execution of the other.
If they were not pure, then we could never know that they’re independent. In that case, we’d have to rely on the order that they were called in the program to determine their execution order. This is how all Imperative Languages work.
The second thing that must be true for independence is that the output of one function is not used as the input of the other. If this was the case, then we’d have to wait for one to finish before starting the second.
In this case, upperMessage and quotedValue are both pure and neither requires the output of the other.
Therefore, these 2 functions can be executed in ANY ORDER.
The compiler can make this determination without any help from the programmer. This is only possible in a Pure Functional Language because it’s very difficult, if not impossible, to determine the ramifications of side-effects.
The order of execution in a Pure Functional Language can be determined by the compiler.
This is extremely advantageous considering that CPUs are not getting faster. Instead, manufactures are adding more and more cores. This means that code can execute in parallel at the hardware level.
Unfortunately, with Imperative Languages, we cannot take full advantage of these cores except at a very coarse level. But to do so requires drastically changing the architecture of our programs.
With Pure Functional Languages, we have the potential to take advantage of the CPU cores at a fine grained level automatically without changing a single line of code.
Type Annotations
In Statically Typed Languages, types are defined inline. Here’s some Java code to illustrate:
public static String quote(String str) {
return "'" + str + "'";
}
Notice how the typing is inline with the function definition. It gets even worse when you have generics:
private final Map<Integer, String> getPerson(Map<String, String> people, Integer personId) {
// ...
}
I’ve bolded the types which makes them stand out but they still interfere with the function definition. You have to read it carefully to find the names of the variables.
With Dynamically Typed Languages, this is not a problem. In Javascript, we can write code like:
var getPerson = function(people, personId) {
// ...
};
This is so much easier to read without all of that nasty type information getting in the way. The only problem is that we give up the safety of typing. We could easily pass in these parameters backwards, i.e. a Number for peopleand an Object for personId.
We wouldn’t find out until the program executed, which could be months after we put it into production. This would not be the case in Java since it wouldn’t compile.
But what if we could have the best of both worlds. The syntactical simplicity of Javascript with the safety of Java.
It turns out that we can. Here’s a function in Elm with Type Annotations:
add : Int -> Int -> Int
add x y =
x + y
Notice how the type information is on a separate line. This separation makes a world of difference.
Now you may think that the type annotation has a typo. I know I did when I first saw it. I thought that the first -> should be a comma. But there’s no typo.
When you see it with the implied parentheses it makes a bit more sense:
add : Int -> (Int -> Int)
This says that add is a function that takes a single parameter of type Int and returns a function that takes a single parameter Int and returns an Int.
Here’s another type annotation with the implied parentheses shown:
doSomething : String -> (Int -> (String -> String))
doSomething prefix value suffix =
prefix ++ (toString value) ++ suffix
This says that doSomething is a function that takes a single parameter of type String and returns a function that takes a single parameter of type Int and returns a function that takes a single parameter of type String and returns a String.
Notice how everything takes a single parameter. That’s because every function is curried in Elm.
Since parentheses are always implied to the right, they are not necessary. So we can simply write:
doSomething : String -> Int -> String -> String
Parentheses are necessary when we pass functions as parameters. Without them, the type annotation would be ambiguous. For example:
takes2Params : Int -> Int -> String
takes2Params num1 num2 =
-- do something
is very different from:
takes1Param : (Int -> Int) -> String
takes1Param f =
-- do something
takes2Param is a function that requires 2 parameters, an Int and another Int. Whereas, takes1Param requires 1 parameters a function that takes an Int and another Int.
Here’s the type annotation for map:
map : (a -> b) -> List a -> List b
map f list =
// ...
Here parentheses are required because f is of type (a -> b), i.e. a function that takes a single parameter of type a and returns something of type b.
Here type a is any type. When a type is uppercased, it’s an explicit type, e.g. String. When a type is lowercased, it can be any type. Here a can be Stringbut it could also be Int.
If you see (a -> a) then that says that the input type and the output type MUST be the same. It doesn’t matter what they are but they must match.
But in the case of map, we have (a -> b). That means that it CAN return a different type but it COULD also return the same type.
But once the type for a is determined, a must be that type for the whole signature. For example, if a is Int and b is String then the signature is equivalent to:
(Int -> String) -> List Int -> List String
Here all of the a’s have been replaced with Int and all of the b’s have been replaced with String.
The List Int type means that a list contains Ints and List String means that a list contains Strings. If you’ve used generics in Java or other languages then this concept should be familiar.
Taking that first step to understanding Functional Programming concepts is the most important and sometimes the most difficult step. But it doesn’t have to be. Not with the right perspective.
Previous parts: Part 1, Part 2, Part 3, Part 4, Part 5
Now What?
Now that you’ve learned all this great new stuff, you’re probably thinking, “Now what? How can I use this in my everyday programming?”
It depends. If you can program in a Pure Functional Language like Elm or Haskell, then you can leverage all of these ideas. And these languages make it easy to do so.
If you can only program in an Imperative Language like Javascript, as many of us must, then you can still use a lot of what you’ve learned but there will be a great deal more discipline required.
Functional Javascript
Javascript has many features that let you program in a more functional manner. It’s not pure but you can get some immutability in the language and even more with libraries.
It’s not ideal, but if you have to use it, then why not gain some of the benefits of a Functional Language?
Immutability
The first thing to consider is immutability. In ES2015, or ES6 as it was called, there is a new keyword called const. This means that once a variable is set, it cannot be reset:
const a = 1;
a = 2; // this will throw a TypeError in Chrome, Firefox or Node
// but not in Safari (circa 10/2016)
Here a is defined to be a constant and therefore cannot be changed once set. This is why a = 2 throws an exception (except for Safari).
The problem with const in Javascript is that it doesn’t go far enough. The following example illustrates its limits:
const a = {
x: 1,
y: 2
};
a.x = 2; // NO EXCEPTION!
a = {}; // this will throw a TypeError
Notice how a.x = 2 does NOT throw an exception. The only thing that’s immutable with the const keyword is the variable a. Anything that a points to can be mutated.
This is terribly disappointing because it would have made Javascript so much better.
So how do we get immutability in Javascript?
Unfortunately, we can only do so via a library called Immutable.js. This may give us better immutability but sadly, it does so in a way that makes our code look more like Java than Javascript.
Currying and Composition
Earlier in this series, we learned how to write functions that are curried. Here’s a more complex example:
const f = a => b => c => d => a + b + c + d
Notice that we had to write the currying part by hand.
And to call f, we have to write:
console.log(f(1)(2)(3)(4)); // prints 10
But that’s enough parentheses to make a Lisp programmer cry.
There are many libraries which make this process easier. My favorite one is Ramda.
Using Ramda we can now write:
const f = R.curry((a, b, c, d) => a + b + c + d);
console.log(f(1, 2, 3, 4)); // prints 10
console.log(f(1, 2)(3, 4)); // also prints 10
console.log(f(1)(2)(3, 4)); // also prints 10
The function definition isn’t much better but we’ve eliminated the need for all those parenthesis. Notice that we can apply as many or as few parameters as we want each time we invoke f.
By using Ramda, we can rewrite the mult5AfterAdd10 function from Part 3and Part 4:
const add = R.curry((x, y) => x + y);
const mult5 = value => value * 5;
const mult5AfterAdd10 = R.compose(mult5, add(10));
It turns out that Ramda has a lot of helper functions for doing these sorts of things, e.g. R.add and R.multiply, which means we can write less code:
const mult5AfterAdd10 = R.compose(R.multiply(5), R.add(10));
Map, Filter and Reduce
Ramda also has its own versions of map, filter and reduce. Although these functions exist in Array.prototype in vanilla Javascript, Ramda’s versions are curried:
const isOdd = R.flip(R.modulo)(2);
const onlyOdd = R.filter(isOdd);
const isEven = R.complement(isOdd);
const onlyEven = R.filter(isEven);
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(onlyEven(numbers)); // prints [2, 4, 6, 8]
console.log(onlyOdd(numbers)); // prints [1, 3, 5, 7]
R.modulo takes 2 parameters. The first is the dividend (what’s being divided) and the second is the divisor (what we’re dividing by).
The isOdd function is just the remainder of dividing by 2. A remainder of 0 is falsy, not odd, and a remainder of 1 is truthy, odd. We flipped the first and second parameters of modulo so that we could specify 2 as the divisor.
The isEven function is just the complement of isOdd.
The onlyOdd function is the filter function with the predicate (a function that returns a boolean) of isOdd. It’s waiting for the list of numbers, its final parameter, before it executes.
The onlyEven function is a filter that uses isEven as its predicate.
When we pass numbers to onlyEven and onlyOdd, isEven and isOdd get their final parameters and can finally execute returning the numbers we’d expect.
Javascript Shortcomings
With all of the libraries and language enhancements that have gotten Javascript this far, it still suffers from the fact that it’s an Imperative Language that’s trying to be all things to all people.
Most front end developers are stuck using Javascript in the browser because it’s been the only choice for so long. But many developers are now moving away from writing Javascript directly.
Instead, they are writing in a different language and compiling, or more accurately, transpiling to Javascript.
CoffeeScript was one of the first of these languages. And now, Typescript has been adopted by Angular 2. Babel can also be considered a transpiler for Javascript.
More and more people are taking this approach in production.
But these languages started with Javascript and only made it slightly better. Why not go all the way and transpile to Javascript from a Pure Functional Language?
Elm
In this series, we’ve looked at Elm to help understand Functional Programming.
But what is Elm? And how can I use it?
Elm is a Pure Functional Language that compiles to Javascript so you can use it to create Web Applications using The Elm Architecture, aka TEA (this architecture inspired the developers of Redux).
Elm programs do NOT have any Runtime Errors.
Elm is being used in production at companies such as NoRedInk, where Evan Czapliki the creator of Elm now works (he previously worked for Prezi).
See this talk, 6 Months of Elm in Production, by Richard Feldman from NoRedInk and Elm evangelist for more information.
Do I have to replace all of my Javascript with Elm?
No. You can incrementally replace parts. See this blog entry, How to use Elm at Work, to learn more.
Why learn Elm?
- Programming in a Pure Functional Language is both limiting and freeing. It limits what you can do (mostly by keeping you from shooting yourself in the foot) but at the same time it frees you from bugs and bad design decisions since all Elm programs follow The Elm Architecture, a Functionally Reactive Model.
- Functional Programming will make you a better programmer. The ideas in this article are only the tip of the iceberg. You really need to see them in practice to really appreciate how your programs will shrink in size and grow in stability.
- Javascript was initially built in 10 days and then patched for the last two decades to become a somewhat functional, somewhat object-oriented and a fully imperative programming language.
Elm was designed using what has been learned in the last 30 years of work in the Haskell community, which draws from decades of work in mathematics and computer science.
The Elm Architecture (TEA) was designed and refined over the years and is a result of Evan’s thesis in Functional Reactive Programming. Watch Controlling Time and Space to appreciate the level of thinking that went into the formulation of this design. - Elm is designed for front-end web developers. It’s aimed at making their lives easier. Watch Let’s Be Mainstream to better understand this goal.
The Future
It’s impossible to know what the future will hold, but we can make some educated guesses. Here are some of mine:
There will be a clear move toward languages that compile to Javascript.
Functional Programming ideas that have been around for over 40 years will be rediscovered to solve our current software complexity problems.
The state of hardware, e.g. gigabytes of cheap memory and fast processors, will make functional techniques viable.
CPUs will not get faster but the number of cores will continue to increase.
Mutable state will be recognized as one of the biggest problems in complex systems.
I wrote this series of articles because I believe that Functional Programming is the future and because I struggled over the last couple of years to learn it (I’m still learning).
My goal is to help others learn these concepts easier and faster than I did and to help others become better programmers so that they can have more marketable careers in the future.
Even if my prediction that Elm will be a huge language in the future is wrong, I can say with certainty that Functional Programming and Elm will be on the trajectory to whatever the future holds.
I hope that after reading this series, you feel more confident in your abilities and your understanding of these concepts.
I wish you luck in your future endeavors.
Repost from https://medium.com/@cscalfani