I have often said that that object-oriented programming’s greatest strength is that it’s teachable, that people “get it.” This is not often said about functional programming. I am no expert on functional programming, but here’s my amateur’s take:
Functional programming is a sequence of FARTS.
I say that the teachable core of functional programming consists of starting with a sequence of data, and then Filtering, Assigning, Reducing, Transforming and Slicing. One of the reasons why “Map/Reduce” is more than a buzzword is that it promotes two of the same ideas. (“Map” is the function name associated with what I call “Transforming,” starting with, say, a string and then working with the date that it can be parsed to.)
You “Filter” unused data and “Slice” it into like-typed sequences, which you “Reduce” to more concentrated value (calculating sums and averages, say). Once “Assigned,” the resulting value of any one of these processes is likely to not need to change (most likely, you just take that result and do more FARTS on it).
One of the repeated questions I hear with my colleagues exploring functional programming is, “Where does the mindset differ?” Time and again I’ve heard (and heard myself say!), “I can follow this code, and I can see how it produces the result, but I don’t know that this is the code I would write if I sat down to solve this problem, and I don’t know what would make this approach the first thing that I think of.”
While I have no doubt that some people slam down a book on Category Theory, cry “Eureka!” and start coding parser combinators in Haskell, I’ve always been more of a “Fake it ’til you make it” kind of programmer. It’s served me well enough for more than three decades and, for my fellow fakers, I say: “Start FARTing.”
I say that what you can do is cast most problems into “I start with some sequence of values that, ultimately, I have to transform into another sequence of values (perhaps of length 1).” If you’re thinking about solving a Sudoku puzzle, there’s a sequence of grids and lines of boxes that need to be filled in, and a sequence of possibilities for each box. If you’re thinking about taxes, there’s a sequence of prices and a sequence of taxation rules. If you’re thinking about a location application, there’s a sequence of GPS coordinates and a sequence of geofences.
Is that enough? No, of course not, but neither is the “Well, what are the real-world objects?” that might be the OOP starting spot. OOP’s teachable catchphrases, “Objects model things in the real world” and “Programs are networks of cooperating objects,” aren’t bandied about daily in professional teams, but there is a foundation, way down deep, that relates OOP to simulation. (All the way to its origins in Simula 67, which explicitly targeted the simulation domain.)
Clarity in OOP comes as you discover collaborations between objects and complications of their interactions, while clarity in FP comes as you develop collections of similar data: the ZIP codes of last month’s customers, the total sales of SKUs that rely on suppliers who have announced price changes, etc.
The greatest philosophical difference between OOP and FP is certainly that OOP advocates creating data structures (objects) whose values (instance variables) can change over time as more information is collected or calculations are performed, and the system is built of a whole bunch of these cooperating state machines. FP, on the other hand, is quite firm that once a value has been assigned to a “variable”, it ought to be unchangeable.
Objects will generally have “all the stuff that might relate” to a calculation, including some mutable state, but FP will generally have “just the stuff I need.” This is frustrating at first to an OOP developer because discovering what stuff’s needed is a major part of the task and it’s often all just a dot away in OOP, while in FP, you might have to thread it down through a series of calculations or return a partially solved calculation up the call stack until it gets back to the needed “stuff.” On the other hand, having so much “at hand” can mean that when you return to the problem, it’s impossible to see through the clutter. If all of the context you need to solve a problem is laid out one argument after another in the function signature, maintenance can be easier.
You may have noticed that I’ve only casually used phrases like “like-minded data” and “similar types,” and I can imagine that there are some whose FARTS would feature “Types” (and switch “Transform” to “Apply”—but then what initial are they going to use for immutability?). There is no question that the issue of “What types are the arguments and return values of this function?” is an enormous part of FP. But whether that reasoning is enforced by a type system is not, I think, fundamental to “getting” functional programming. I recently reviewed two quite-good books on functional programming in JavaScript and passed them on to my nephew, who must use that language in a first-year college engineering course (and must program in Notepad! The horror!).
More important than the specifics of the type system, I think, is this idea of sequences, whether of length 0, 1 or n. In many ways, my “sequence of FARTS” could be rephrased as coming to appreciate the power of Processing LISts. But PLIS? That’s a terrible acronym. It would never catch on.
Larry O’Brien is a developer evangelist/advocate for Xamarin. Read his blog at www.knowing.net.