Functional Paradigm: Concepts and Guidelines
Learn about the main concepts that compose the functional paradigm.
In this lesson, we’ll take a look at the concepts of functional programming and their application in Clojure. Don’t worry about understanding the code yet; we’re going to be talking about all of it in the following lessons.
Immutability
Immutability is the main characteristic of functional programming. It consists of the principle of variables, which are read-only structures, meaning we’re not able to change the state of those variables during the execution of a system. Every time we feel like modifying a variable, immutability will take us to the creation of a new variable with the content of the previous one plus whatever we need to include or exclude.
Furthermore, immutability has the remarkable ability to improve the consistency of services. This is because it makes the developers more aware of the state of the service and of what has been going on throughout the execution. So, testing and debugging are simpler because we have full control over the state of the service at each stage.
As we can see, immutability is the opposite of the imperative paradigm, and understanding this concept will guarantee a change in our mindset when we start coding.
Moreover, at this point, it’s important to start thinking about how to solve problems without using state (mutable) variables.
Clojure example
First-class functions
First-class functions are functions that are treated as any other variable in the programming language. In such a language, a function can be passed as an argument to other functions, can be returned by another function, and can be assigned as a value to a variable.
Clojure example
Higher-order functions
Higher-order functions are functions that perform operations over other functions. These functions perform the action of receiving a function as an argument or returning functions as a response.
Clojure example
This example is the same as the previous one. The higher-order functions in this example are other-func, which is receiving a function as an argument and executing it, and another-func, which is returning the function without executing it.
Pure functions
Pure functions are functions that have a single possible return for an input. So we’re able to predict their result based on the input that we’re passing. They might be understood as a mathematical function. If we have
Clojure example
Function composition
Function composition is the process of composing the solution to a problem combining small units and functions with small responsibilities. It’s a flexible and powerful way of organizing code in which the input of a function comes from the output of the previous one.
Compared to object-oriented programming, in functional programming, function composition takes the place of inheritance when a class derives from another class, inheriting all the public and protected properties and methods from the parent class.
Function composition is closely related to a fundamental mindset shift, which involves the transformation of elements without associating them with variables and symbols. This approach contrasts with manipulating elements using auxiliary variables.
Clojure example
Expressions
Expressions are variables, symbols, or functions that have a value. In functional programming, because we do things with immutability and with functions as our main resource, we want to make sure that our functions are all expressions and have a return value. So, we try to avoid statement functions, which are functions with instructions, logic, and no return, which are pretty common in imperative paradigms.
Clojure example
Expressions allow us to do a much more precise test. Like in any mathematical expression, we’re able to know the exact result based on the variables received.