This article was created for those who want to use functional programming in their career or who are learning new programming paradigms.
We will examine the basics of functional programming and how to apply it in Python. Good readings!
Introduction to Functional Programming
Functional Programming is a popular programming paradigm closely linked to the mathematical foundations of computer science.
Python is not a functional programming language, but it supports it because it is a multi-paradigm programming language.
Why Do You Need Functional Programming?
Functional programming allows you to write easy-to-read codes and also provides convenience in your debugging process.
In addition, it allows you to make your codes more reliable. You can diagnose security problems more quickly.
While the effects we mentioned are very good for software, in some cases the performance of functional programming is bad.
Some Important Information For Starting
There are several terms that will be used frequently in this article, and in this section, we will examine those terms.
If the Function accesses and operates on something other than a parameter directly given to it, it is called a side-effect.
In functional programming, a function cannot access or manipulate external variables, including the input it receives, otherwise, side effects will occur.
The rules here can be bent by project, but you should try to limit them in functional programming.
Concepts For Functional Programming
Functions are the most important thing in the functional programming paradigm, but not every function is suitable for functional programming.
In this section, we will learn what to watch out for those who will be dealing with functional programming and how this affects their code.
1 – Pure Functions
The biggest rule of thumb of functional programming is that you should never manipulate the input you receive. (you should not mutate).
If you do not mutate the parameter, the readability of your code will increase. Also, since there are no side effects, you always get the same result with the same input.
Functions that do not manipulate the parameters they receive and do not use external variables are called pure functions.
# Pure Function def double(arr): newArr =  for i in arr: newArr.append(i * 2) return newArr # Impure Function def double(arr): for i in len(arr): arr[i] = arr[i] * 2 return arr
You will need separate functions for other tasks as pure functions only do 1 task. You should combine these pure functions.
You can combine pure functions by using the output produced by your first pure function as the parameter of the other function.
# First Pure Function def increase2(arr): cArr = arr for i in range(len(cArr)): cArr[i] = cArr[i] + 2 return cArr # Second Pure Function def getDouble(arr): cArr = arr for i in range(len(cArr)): cArr[i] = cArr[i] * 2 return cArr # Combine Functions arr = [1,3,4,5,6] val = increase2(getDouble(arr))
Thanks to the merge here, we were able to increase the elements by 2 after multiplying the array.
Pure variables have a downside: if you have a large data entry, copying it won’t perform well (don’t convert functions with big data entries to pure functions).
2 – Higher Order Functions
Let’s explain these functions simply, such functions can take another function as a parameter and return that function again.
These functions give you flexibility and give you the advantage of connecting inputs to other functions.
Also, using these functions, you can perform multiple operations on a parameter. Note that in functional programming, each function does a single task.
def display_array(arr , func): for i in arr: func(i) arr = [1,2,3,4,5] display_array(arr , print) # [1,2,3,4,5]
As you can see in the example here, we keep the print function as a parameter, where the display array function is the High Order Function.
Now let’s observe with a different example why these function structures are important for the program.
# get double index of array def double(arr): newArr =  for i in arr: newArr.append(i * 2) return newArr # get triple index of array def triple(arr): newArr =  for i in arr: newArr.append(i * 3) return newArr # merge manipulated array def merge(arr , func = double , func2 = double): return func(arr) + func2(arr) print(merge([1,2,3,4] , double , triple)) # [2, 4, 6, 8, 3, 6, 9, 12]
This code will give you an advantage in debugging as there are no side effects of the functions.
The reason for using higher-order functions here is that functions after the first function use the return value of a previous function.
Python provides some useful built-in High Order Functions that make working with arrays much easier. Let’s take a look at these functions.
3 – Built-in High Order Functions
High Order Functions available in Python are much more performant than loops, and also allow you to present the code in a shorter and more concise way.
Because of these properties and being a pure function, it is very suitable for functional programming.
This section requires knowing lambda functions, if you don’t know, we recommend reading this article, you can continue later.
1 – Map Function
The map function is used to apply the desired function to each element in an iterable object, it is very short to use and returns an iterator.
As an example, let’s rewrite the function that multiplies each element by 2, which is the pure function we used at the beginning, with a map.
arr = [1,2,3,4,5,6] newArr = map(lambda x: x * 2 , arr) for num in newArr: print(num) # 2 4 6 8 10 12
According to the function we created at the beginning, we have achieved a great increase in efficiency in terms of memory space and speed.
2 – Filter Function
The filtering function is another useful function that is used to separate the data in the feature we specify.
arr = [10,20,30,40,50] newArr = filter(lambda x: x * 2 > 50, arr) for num in newArr: print(num) # 30 40 50
The function is easy to understand. Elements that do not satisfy the condition are not added to the variable, the condition here depends on the lambda function.
You can use these two functions in combination with each other, after all, these functions return an iterator.
# 0 to 20 numbers nums = range(0,20) # filter odd numbers filterNums = filter(lambda x: x % 2 == 0 , nums) # get double of even number newNums = list(map(lambda x: x * 2, filterNums)) print(newNums) # [0, 4, 8, 12, 16, 20, 24, 28, 32, 36]
To run the result returned by the Map function without loop, we have converted it into a list, now you know how to use the 2 functions together.
You can also nest functions instead of assigning them to variables, but it can be difficult to read, so it’s better to assign functions to different variables.
4 – List Comprehensions
Another feature found in functional programming languages and also found in Python is List Comprehensions.
With this feature, you can perform quick operations on lists, just like map and filter (these two features have advantages and disadvantages amongst themselves.)
# Array For Naruto Fans names = ["sasuke","sakura","naruto","pain","madara","itachi"] # Capitalize the first letters trueNames = [i.capitalize() for i in names] # Display List print(trueNames) # ['Sasuke', 'Sakura', 'Naruto', 'Pain', 'Madara', 'Itachi']
In accordance with functional programming, inputs do not mutate with list comprehensions. Unlike map and filter, it returns a list instead of an iterator.
nums = [1,2,3,4,5] double = [i * i for i in nums if i > 2] # [9 , 16 , 25]
In the example here, the loop only works on items greater than 2. Now that we have learned the necessary concepts, we can move on to the last word.
In this article, we examined the advantages of functional programming and how it can be used with Python.
You can make your code suitable for functional programming by paying attention to the rules specified here and using structures.
Since functional programming is a rapidly growing programming paradigm, it can take you forward in the industry.