Functional Programming

  • Tutorial

Python and functional programming:

Functional Programming is a coding style that focuses on defining what to do, instead of performing some action. Functional programming is derived from the mathematical style of thinking where you define the kind of inputs that go into a function and the kind of outputs that we can expect from the function.In functional code, the output of the function depends only on the arguments that are passed. Calling the function f for the same value of x should return the same result f(x) no matter how many times you pass it. Thus, it calls for a radically different style of thinking where you are rarely changing state. Instead of moving through steps, you think of data as undergoing transformations with the desired result as the end state.

Python has many constructs that enable a programmer to dabble in functional programming. If you want to know more on functional programming, take a look at our notes on the topic.

In this tutorial you will look at:

  1. What are the characteristics of functional programming
  2. How to achieve those characteristics.
  3. What is the meaning of using functions as first class objects.
  4. What is functional purity.
  5. How to refactor procedural code to functional code.

Characteristics of functional programming

A functionally pure language should support the following constructs:

  • Functions as first class objects, which means that you should be able to apply all the constructs of using data, to functions as well.
  • Pure functions; there should not be any side-effects in them
  • Ways and constructs to limit the use of for loops
  • Good support for recursion

Functions as first class objects in python:

Using functions as first class objects means to use them in the same manner that you use data. So, You can pass them as parameters like passing a function to another function as an argument. For example, in the following example you can pass the int function as a parameter to map function.

>>> list(map(int, ["1", "2", "3"]))
[1, 2, 3]

You can assign them to variables and return them. For example, in the following code, you can assign the function hello_world, and then the variable will be executed as a function.

>>> def hello_world(h):
...     def world(w):
...         print(h, w)
...     return world # returning functions
...
>>> h = hello_world # assigning
>>> x = h("hello") # assigning
>>> x
<function world at 0x7fec47afc668>
>>> x("world")
('hello', 'world')

You can store functions in various data structures. For example, in the following code you can store multiple functions in a list.

>>> function_list = [h, x]
>>> function_list
[<function hello_world at 0x7fec47afc5f0>, <function world at 0x7fec47afc668>]

Python functional purity:

There are various built-in functions in Python that can help to avoid procedural code in functions. So something like this

def naive_sum(list):
    s = 0
    for l in list:
        s += l
    return s

can be replaced with the following construct:

sum(list)

Similarly, built-in functions such as map, reduce, and the itertools module in Python can be utilized to avoid side-effects in your code.

Reducing the usage of loops in Python:

Loops come into the picture when you want to loop over a collection of objects and apply some kind of logic or function.

for x in l:
    func(x)

The above construct stems from the traditional thinking of visualizing the whole program as a series of steps where you define how things need to be done. Making this more functional will need a change in the thinking pattern. You can replace the above for loop in Python in the following manner.

map(func, l)

This is read as “map the function to the list,” which conforms to our idea of defining the question “what.”

If you take this idea and apply it to the sequential execution of functions, you get the following construct.

def func1():
    pass

def func2():
    pass

def func3():
    pass

executing = lambda f: f()
map(executing, [func1, func2, func3])

Please note that this does not actually run the functions but returns a lazy map object. You need to pass this object to a list or any other eager function to have the code executed.

Python Recursion:

What is Recursion

Recursion is a method of breaking a problem into subproblems which are essentially of the same type as the original problem. You solve the base problems and then combine the results. Usually this involves the function calling itself.

An example for recursion may be something like:

eat the dumplings: 1. check how many dumplings on the plate 2. if no dumplings left stop eating 3. else eat one dumpling 4. "eat the dumplings"

How to implement recursion in your code

Python functions support recursion and hence you can utilize the dynamic programming constructs in the code to optimize them. Recursion basically needs to fulfill two conditions. There should be a condition where the recursion should end, and it should call itself for all other conditions. The end condition should be limiting; i.e, the functions should call smaller versions of themselves.

Example: The following code generates Fibonacci numbers through recursion.

def fib(n):
    if n == 0: return 0
    elif n == 1: return 1
    else: return fib(n-1)+fib(n-2)

A small example showing how to convert procedural code into functional code:

Let us go through a small example where you try to refactor procedural code into functional. In the below example, you have a starting number which gets squared, the result is incremented by 1 and the result of that is raised to the power of 3, the code then takes the decrement. Note that the code works in steps.

# procedural code
starting_number = 96

# get the square of the number
square = starting_number ** 2

# increment the number by 1
increment = square + 1

# cube of the number
cube = increment ** 3

# decrease the cube by 1
decrement = cube - 1

# get the final result
result = print(decrement) # output 783012621312

The same procedural code can be written functionally. Note that unlike the code above instead of giving explicit instructions on how to do it, you are giving instructions on what to do. The functions below operate at a higher plane of abstraction.

# define a function `call` where you provide the function and the arguments
def call(x, f):
    return f(x)

# define a function that returns the square
square = lambda x : x*x

# define a function that returns the increment
increment = lambda x : x+1

# define a function that returns the cube
cube = lambda x : x*x*x

# define a function that returns the decrement
decrement = lambda x : x-1

# put all the functions in a list in the order that you want to execute them
funcs = [square, increment, cube, decrement]

# bring it all together. Below is the non functional part. 
# in functional programming you separate the functional and the non functional parts.
from functools import reduce # reduce is in the functools library
print(reduce(call, funcs, 96)) # output 783012621312
Contributed by: Joydeep Bhattacharjee
Notifications
View All Notifications