Ahhhh I can already hear you screaming and sighing: “More post about Functional Programming, what is the big deal about it? Why should I change my way of thinking, now?”
Try to turn those questions around and ask yourself : we are talking about programming here, maybe because it will help you?
Maybe it can make your code easier to read and more maintainable?
Are you chill, now? Alright, let us tackle some “fears” (even though they shouldn’t be) about Functional Programming (FP), shall we ?
We will use Purescript in our examples since it is more concise and easier to read than pure JS.
Basic introduction to FP terms and paradigm (Using Purescript VS Pure JS)
First, I would like to get you familiar with some basic concepts about FP. Functional Programming, as the name sugests,
is based on the Functional Paradigm (You don’t say?) where everything is a Function, those functions that we love from mathematics (trigger word), remember? From A to B, or from Integer to Integer you name it.
addMeFive :: Int -> Int addMeFive x = x + 5
return x + 5
[/code] If you remember correctly, functions, by definition, when receiving the same input over and over again will
return the same result every time (Pure functions).
addMeFive 5 = 10 -- and there is no way of getting any other answer from this call.
These little fellows have cool properties like composition which is the basis to create more complex programs in FP.
Composition is not the only way of gluing functions together
Composition of functions f and g.
g :: a -> b f :: b -> c
If there is a function from a to b and another from b to c then there is also a function from a to c and can be defined by the composition of the two latter functions.
-- f <<< g reads - f after g f <<< g :: a -> c
Variables are immutable, by default or if not, it must be clearly stated.
a=5 a = 8 -- is not allowed.
As you can probably see, if variables are immutable, then race conditions are not a problem since it is a consequence
of mutable state. So, in FP, concurrency and parallel operation are easier to deal with.
Types are extremely important in Functional Programming.
Not every functional programming languages are strongly typed, types encourage us, however to think first about the relationships in our Software instead of sprinting and coding mindlessly.
A special kind of types are polymorphic types. Polymorphism enables us to use the same function but with different Input Types, these types built the cornerstone for the generic types known in OOP languages like Java, C# and so on.
length :: [a] -> Int -- returns the length of a List of type a
After the basics, one of the important aspects of functional programming is Higher Order functions (HOF).
It is where functions become interesting, we know functions receive an input and return an output, until now it was only Integers, Strings, a random type a, etc.
What if we give a function as an argument? That’s it, you have just upgraded your function.
map :: (a->b) -> [a] -> [b]
map is a function which returns a list where the function given as argument was applied to each element of the given list.
mapis quite an important function, so keep it in mind.
Abstraction: OOP vs FPNow, we have some (very) basic understanding about FP, let’s talk about abstraction for a second.
Definition of Abstraction (that better suites Computer Science): “The quality of dealing with ideas rather than events.”
We do not want to deal with concrete, or detailed, events because there are too many factors which will block our way of thinking, so we abstract, losing some of the details but maintaining the focus of the problem (the ideas of the definition).
To be more concise, we handpick the most important parts of our problem and the remaining details are forgotten, easing not only the structure for our types/objects but also our overall programs.
In OOP, the abstraction is quite simply achieved by representing “Things”, though, not in all its complexity,
only the important properties. Then you can do “Stuff” with the abstracted entity, and it is pretty much it.
By the way, the “Thing” is called Object and “Stuff” is Method.
In FP, we try to max out the abstraction, we cut our problems into simple functions which will after be composed to create more complex functions resulting into a program that does the thing we wanted. It is not only focused on the representation of “Things”, it is more about the relations between them, which is ultimately our focus. We create our basic types and then, if we need to have more complex types, we can combine them with various operators e.g. A + B (Either A or B or the Union Type), A x B (A times B, Or the pair type) and a few others.
FP Patterns 101
There we are, the real point of all this rambling, FP patterns, not to be confused with the Design Patterns from OOP, FP patterns is about recognizing repetition, you know, the real meaning of patterns (you need to try harder OOP).
Let’s then talk about Currying, Functors, Catamorphism and Anamorphism (or respectively, Currying, Map, Fold and Unfold). For the sake of simplicity, I will use Lists to explain the last three:
Curry (not the dish) is what we do when we transform functions with more than one argument into functions which receives one argument and then returning a function responsable for receiving the remaining arguments. This eases the possibility of composition/Chaining.
curry :: ((a,b)->c) -> a -> b -> c
Map aka Functor
Map aka Functor is the application of a function in a complex structure. For lists, it looks like:
map :: (a->b) -> [a] -> [b]
e.g. When you want to double the elements of a list, instead of the good old for loop, why not:
map ((elem)=> elem * 2) [1,2,3] = map (*2) [1,2,3] = [2,4,6]
Reduce aka Catamorphism aka Fold
Catamorphism from the Greek: κατά “downwards” and μορφή “form, shape” or also known Fold is the ability to reduce a structure into another structure, also know as the Conquer from Divide and Conquer.
fold :: forall a b c . (a->b->b) -> b -> [a] -> b
e.g Want to compute the somation of a list of integers? No problem
fold ((elem,acc)=> acc + elem) 0 [1,2,3] = 6
To be more explicit, fold is the recursive function with input type list and output whatever type you want. If we deconstruct our example in the corresponding function :
sum :: [int] -> int sum  = 0 -- second argument of our fold sum (x:xs) = x + sum xs -- same behaviour as the functions received as argument in our fold example
Generate aka Anamorphism aka Unfold
Anamorphism from the Greek ἀνά “upwards” and μορφή “form, shape” or also known as Unfold is the ability to generate a structure from another structure, the Divide of the Divide and Conquer.
unfold :: (b->Maybe (Tuple a b)) -> b -> [a]
This seems more complicated however the function
(b->(Tuple a b)) is responsible for generating the elements of the output list.
e.g. generate list from 10 to 1
unfold (seed -> if seed == 0 then Nothing else Just(seed,seed-1)) 10 = [10,9,8,7,6,5,4,3,2,1] generateList:: Int -> [Int] generateList seed = if seed == 0 then  else seed:(generateList seed-1)
A Shift towards FP
Written by Yoan Ribeiro
PS : You can take a look to my talk and the talk of BloodyOwl (in French) about PureScript and Reason there :