Trying to grasp basic functional paradigms

As I am familiar to python, I will try to grasp functional paradigms in python first.

Closures

I am starting with a very simple building block of FP, called closures. Closures allow the programmer to embed values in functions that are only accessible to that function and return another function.

This sounds weird at first and it took me some time to wrap my head around it, but it is a simple concept once understood.

Let's have a look at this example:


In [2]:
def add(a):
    def add_b_to_a(b):
        return a+b
    return add_b_to_a

I defined a function add that takes one argument, an integer with value a. Instead of returning a value, this function returns another function, add_b_to_a.

The magic that happens is that the value of a, which was passed to the outer function will now forever be enclosed in the function that gets returned. I can now create functions that have some state "injected" into them. This lays the grounds for further functional concepts like currying etc.

By defining a function "add_to_four" that calls add with a=4, we create a function that will always return the result of the "inner"function, with the value of a = 4.


In [3]:
add_to_four = add(4)

If I now call this new function with b = 8, then the result will be 4 + 8 = 12


In [4]:
add_to_four(8)


Out[4]:
12

It is possible to create many functions that are just adding different fixed numbers to a number


In [7]:
add_to_two = add(2)
add_to_ten = add(10)

In [10]:
# this should return 12 
add_to_ten(0) + add_to_two(0)


Out[10]:
12

Map/Reduce logic

A lot of concepts in FP rely on employing map/reduce concepts. This is not a clear FP paradigm, but a useful pre-condition for this.

A map function takes two arguments, a function and a collection of items. This is a very simple example:


In [14]:
listt = ["one","two","three"]
type(listt)
lmap = map(len, listt)
lmap


Out[14]:
[3, 3, 5]

This map function mapped the length of the individual strings in the collection listt to this list, i.e., replaced the original elements of the collection with its string lengths.

The reduce function applies a reduction function on a collection of items and returns an aggregate. The following code is a simple example of this: It takes the lenghts of the string in the preceding map function and reduces them to the sum of their lenghts, returning a simple scalar value


In [17]:
lreduce = reduce(lambda a,x: a+x,lmap)
lreduce


Out[17]:
11

So, what does the a,x pair mean? The very nice explanation of https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming states this:

 x is the current item being iterated over. a is the accumulator. It is the value returned by the execution of 
 the lambda on the previous item. reduce() walks through the items. For each one, it runs the lambda on 
 the current a and x and returns the result as the a of the next iteration.

 What is a in the first iteration? There is no previous iteration result for it to pass along. reduce() uses the first item in the collection for a in the first iteration and starts iterating at the second item. That is, the first x is the second item.

This is what actually happens in the aforementioned reduce function:

This first iteration has no "a", thus it will be set to the first "x" on the first iteration. After the first iteration, a is 3. The second iteration looks at the second "x" (3, too) and evaluates the function a+x on both values. The result fro a after the second iteration is now 6. The third iteration now again calculates a+x for the thrid value of x (5). The final result then is 11 (6 +5).