The Essence of Functional Programming
Published: 25/05/2020
Functional Programming (FP) is often described using a lot of jargon. A lot of fluff and no substance. I struggled with understanding FP for quite some time because of this. Even after understanding the concepts and principles involved in FP, I never really knew what FP was.
What is the philosophy behind FP? How does thinking functionally differ from thinking in an OO-way? These are the questions I struggled with often.
Only recently, I came across a section in Will Kurt's Get programming with Haskell that finally made everything click for me. He used the following example to clear up everything I had been confused about. Let me take you through it.
We will take an example of a programming problem and solve it in a functional way. The key takeaway for you from this should be seeing how a functional programmer would think about a problem, how she would think about the flow of data and apply behavior differently on data as compared to an OO programmer.
Suppose you have a large text document and you need to find all the numbers in that document and then add them all together. How would a functional programmer solve this problem?
-
Let's start with knowing that a document can be represented as a
String
-
The logical first step now is somehow to convert this text document into a form which we can use to search for numbers. One way to go about that is converting this
String
text document into a list ofString
s that we can use to search. To do this, we can write a function with the following definition:String -> [String]
-
Next, we will write a transformation to search for numbers. This will take our list of
String
s along with a function to check whether aString
is a number or not, and will finally return a filtered list ofString
s ie.[String] -> (String -> Boolean) -> [String]
The transformation above is slightly tricky, especially for novice programmers so lets break it down into smaller chunks to explain it better.
We have a list of String
s that we pass it into a function with the signature String -> Boolean
. This function's job is to use its inner workings to determine if any String
it receives is a number or not. If we call this function F
then its job looks something like this:
F: String -> Boolean F("4") -> True F("hello") -> False
The final transformation (for a particular example input) will look something like this:
[String] -> (String -> Boolean) -> [String] ~ ["4", "hello", "5", "world] -> F -> ["4", "5"]
-
Now at this point, we have numbers but they need to be converted from Strings to numbers. Another transformation:
[String] -> [Integer]
-
And finally, we need to take a list of integers and transform it into a single integer — the total number of numbers in the document:
[Integer] -> Integer
And we're done! By putting small transformations together using functions that do a transformation each, we have solved the problem that we had.
Thinking about the types of transformations that we are going to make, we've been able to design our overall program much the same way we design a single function.
This is the essence of FP. Thinking in terms of high-level transformations is the the core of what FP is. Once we map out our transformations at a high level, we just need to use functions to hash out the details!
This post is part of a larger series of posts under the name 'Neat Examples'. The idea behind this series is to provide examples and analogies to help programmers understand programming concepts with the highest possible chance of retention.