There is no clear, widely-accepted definition of Functional Programming. It is a collection of related featues which cohere well into a very useful style of programming.
Reg Braithwaite has a good description of the central difference between these two paradigms.
OO focuses on the differences in the data, while FP concentrates on consistent data structures.
Is one of these techniques the clear-cut winner in the business world? Is it functional or object-oriented?
SQL is not a functional language per se but it shares the important characteristic of being declarative.
We will take a look a brief look at these functional programming features of other languages first,
then turn our focus to those things we can actually accomplish in Javascript.
For the remainder of this talk, we will use the Ramda library that Michael Hurley and I have been developing. But there are a number of interesting alternatives available:
Converting an imperative Task List application into a functiona version.
We start by fetching something like the following data from the server:
Create a function accepting a `member` parameter that fetches the data, chooses her incomplete tasks, returns the ids, priorities, titles, and due dates of those tasks, sorted by due date.
Since the fetch is asynchronous, we'll hook everything together with promises. Ignore error-checking for now.
(continued on the next slide.)
(continued on the next slide.)
(continued on the next slide.)
We could continue by defining Task
and MinimalTask
, but that's just overkill.
The difference between the imperative and the OO code is mostly organizational. The same code
runs in both; it's just arranged differently. (And it's full of `this
` keywords.
)
This means that we can focus on the simpler imperative code.
We will now convert this code into concise, readable, functional code, one block at a time, explaining some of the basic building blocks of functional programming as we go. First up is this little function:
So the obvious question, then, is, what is the get
function?
get
FunctionThis is the definition of the get
function in the Ramda library:
Ignoring the curry
wrapper, this is pretty simple. get
is a function which accepts
a property name and an object, and returns the property of the object with that name.
Our then
call needs a function. So curry
must be doing something interesting with
this function, which should return an object propery, to instead returning a new function. We need to
take a detour to discuss curry
.
Currying is the process of converting functions that take multiple arguments into ones that, when supplied fewer arguments, return new functions that accept the remaining ones.
Different version of currying work slightly differently. In Ramda, you keep getting back functions until you finally pass the required number of parameters.
Some insist that this is not truly currying, but should be called partial application
. In any
case, it serves the same role as currying does in a more strongly typed language.
get
Remember the definition of get
:
Now that we understand curry
, we can see this is equivalent to *
:
And that means that our new get('tasks')
is equivalent to
*
Technically not quite equivalent. Anyone see why?So far, we've been able to replace this block:
with this one:
The next block to replace looks like this:
We're running a filter on the input list, keeping those that have the correct
member
. Let's do this functionally.
filter
is a very simple function. You pass it a predicate function, which is used to determine if
an individual item should be included, and a list of items. It returns you a new list of those that list
items that made it.
Remembering that the then
block will pass the list of tasks to us, we really want to call filter
with a predicate, getting back a curried function that will accept a list.
Here's a first pass:
(Remember that memberName
was a parameter to our original function.)
So, for one thing, we've reduced the weight of our custom code:
But we've done something more important too: We've moved the focus from iteration and updating the state
of a local collection to the real point of this block: choosing the tasks with the proper
member
property.
An important feature of functional programming is that it makes it easier to focus on the logical issues.
The next block is similar, except that instead of using filter
, we will use reject
,
which behaves exactly the same except that it chooses those members of the list that don't
match the predicate. We replace this code:
with this:
A reasonable question would be why with didn't do this instead, which would work equally well:
Because these two blocks are so similar, we have an early chance to refactor our code:
Both of these functions accept an object and return a boolean that describes whether a particular
property of the object has a given value. Perhaps a good name for a function that generates such
functions would be propEq
. Let's implement that.
propEq
This works, and we could leave it there, but we're going to take another detour into a popular style of
functional programming known as points-free
coding.
The name has nothing to do with '.'
characters. It derives from mathematics and has something
to do with homomorphisms on topological spaces.
Don't worry…
This won't be on the test.
With the functions add
(which adds two numbers) and reduce
(which runs the supplied
function against an accumulator and each element of the list, feeding the result of each call into the next one
and returning the final result), we can easily define a sum
function like this:
Because of the automatic currying, though, the following is entirely equivalent:
This is the points-free style, defining functions without ever making direct reference to their arguments.
There are plenty of reasons to like it, but the most important one might just be the simplicity. There is a great deal to be said for elegant, readable code.
propEq
Can we redefine the following in a points-free style?
Here's a version that is closer to points-free, removing the direct reference to obj
:
Huh? What? compose
? eq
?
eq
is easy: like all good functions of multiple parameters, it's curried, and it simply reports
whether its two arguments are equal. So eq(val)
is a function which reports whether its
parameter has the same value as does val
. But now we need to discuss compose
.
I have another short talk dedicated entirely to techniques of functional composition. This is a very brief overview:
In mathematics f ∘ g
(pronounced "f composed with g") is the function that given x
,
returns f(g(x))
.
So if we follow the mathematical model compose(add1, square)(x)
should equal add1(square(x))
.
Note that Ramda also defines pipe
, which does much the same thing, but runs the functions
in the opposite order. So pipe(add1, square)(x)
equals square(add1(x))
. Both
styles have their uses.
propEq
So now this definition makes sense:
Note the switch from compose
to pipe
.
This gives us a further way to clean it up, and make it entirely points-free, using a useful feature of Ramda we
haven't seen implemented in other libraries, which we call use-over
. Used like
func
using the results of all these.
This gives us the final version of propEq:
Since I wrote the first version of this talk, we've decided that this function is useful enough to include in Ramda
itself, so we didn't actually need to go to the work here of writing it. Still,
all these explanations aside, it was only a minute or two of work to do this refactoring and arrive at a
fairly simple version of propEq
. We would plug it back in like this:
The next block we wanted to update looked like this:
You're a smart bunch, right? I probably don't even have to explain what pick
does, right?
Good, then we can move on to discuss map
.
map
functionIt is not down in any map; true places never are. – Herman Melville
One of the most fundamental functions used in FP is map
, which is used to convert one list into
a related one by running the same function against each member.
There isn't much more to say about map
, but it's important to point out that this function
and reduce
, which we mentioned briefly earlier, are among the most important functional
programming tools around.
We used map
like this:
The magic of currying is again at work here:
pick
accepts a list of properties and an object and return a partial clone, copying those
properties from the original. Since we just pass in the properties, this curried function returns a
new function that accepts an object and returns that partial clone.map
accepts a function and a list an applies the function to the list. But because it's
curried, and because we supply only the function generated by the curried pick
, this one
also returns a new function which will accept a list and create these partial clones of each element in
the list.then
, which will simply pass along its parameter (whenever that
becomes ready) to our function and "return" the result of running our function against it. (We simply
know because of the way prior calls have been built that this will be a list of tasks.)sort
The last segment we wanted to convert looked like this:
We won't discuss the implementation of sortBy
, but the basic idea is that it returns a new list
made from an old one by sorting the elements according to keys generated by the function passed to it. For
instance:
curry
Again, we take advantage of the fact that our important functions are curried, and use
get('dueDate')
. This creates a function that, fed one of our task objects, returns its due date.
We can feed this into sortBy
to get the following:
While this is not a lot less code than the original:
it clearly is a savings. However, much more importantly, the code is all clearly aimed at our problem. The new code is much closer to a direct translation of the English specifications than is the original.
It's important to note that nothing in here is meant to promote the Ramda library in particular.
While I'm certainly partial to it, the only thing that we used in here that was not entirely common to the
majority of functional programming libraries (across many languages, in fact) was the
use().over()
construct, and all that really gained us was to turn a short function into
a points-free one-liner.
Certain libraries make things easier than others, though. The equivalent code using Underscore or LoDash, which don't curry their functions by default, and which choose a different default parameter order, would involve significantly more boilerplate.
We've seen what are probably the most important functions in functional programming:
map
reduce
filter
compose
curry
There's one that to some might be conspicuous by it's absence:
forEach
I would argue that this is not actually appropriate to functional programming, as its main purpose is to help you achieve side-effects. But many libraries do include one.
And through these, we can also achieve
/
#