A Student's Guide to Software Engineering Tools & Techniques »

An Introduction to Functional Programming

Authors: Phang Chun Rong

What is Functional Programming

Functional programming is a programming paradigm that treats computation as the evaluation of mathematical function and avoids mutating state and variables. Unlike imperative programming languages like C, functional programming languages are declarative. Even though this demands a shift in mindset from most programmers who are used to imperative form of programming, functional programming paradigm is still increasingly popular due to its advantages.

Functional Programming Languages

Functional programming is simply a paradigm and needs to be implemented by programming languages. Below are various languages that have explicit support for the functional programming paradigm:

  • Haskell
  • Clojure
  • Elixir
  • Elm
  • Scala
  • ML (Meta Language) family of languages

While functional programming can be implemented by languages like Java, the languages listed above encourage the functional programming paradigm such as pure functions or even enforce them in the case of Haskell.

Concepts in Functional Programming

Pure Functions

Pure functions is one of the concepts in functional programming. To call a function pure, it needs to satisfy two conditions:

  1. Idempotence - The function should return the same output for the same input when invoked arbitrarily many times.
  2. No side effects - The function should not cause side effects like mutating global state.

To illustrate an example of a pure function. Consider this simple example in Python:

# Pure Function
def add(x, y):
    return x + y

Contrast this with an impure function:

# Mutate state
y=0
def add_to_y(x):
    global y
    y = y + x
    return y

We see that the impure function violates both conditions. Running add_to_y multiple times with the same input X would give different value.

Immutability

Another concept in functional programming is immutability. Immutability prevents an object's state to be change after it is created.

Having immutability built into functional programming languages like Haskell helps ensure that functions are pure because mutable variables and states can introduce side-effects.

To know more about immutability in functional languages, you can take a look at:

Techniques in Functional Programming

Recursion

Pure functional languages do not have loop constructs like imperative languages. This is because Iteration usually involves state mutation per iteration. Because functional programming avoids state changes, Recursion is a commonly used technique to replace Iteration. An example of replacing state-mutating iterative code to a pure functional recusive code is shown below:

# Iterative
def getSumOfList(listOfNumbers):
    sum = 0
    for number in listOfNumbers:
        sum += number
    return sum
# Recursive
def getSumOfList(listOfNumbers):
    if len(listOfNumbers) == 0:
        return 0
    return listOfNumbers[0] + getSumOfList(listOfNumbers[1:])

Hence, to be able to write functional languages effectively, it means being able to replace Iteration with Recursion. Here are some guides to help you on that:

Higher Order Functions

Higher Order Functions are functions that either take functions as parameters, return a function, or both. As functions are first class citizens in functional programming languages, this allows functions to be passed around like objects and values.

One example of Higher Order Functions is map, which takes in a function and a collection of objects.

length_of_names = map(len, ['Alex', 'Thomas', 'John'])
print(length_of_names) # [4,6,4]

map takes in 2 parameters, a function and a collection. map returns a new collection whose elements are the result of applying the given function on the elements of the given collection. In the given example, map returns [len('Alex'), len('Thomas'), len('John')]

There are useful functions and techniques that are based off Higher Order Functions in Functional programming.

Advantages of Functional Programming

The common question when learning about functional programming is what's the point of having us going through all the trouble of having pure functions, state immutability and absence of loops. Turns out, there are various positive implications of functional programming:

Disadvantages of Functional Programming

Functional programming is not a new concept and has been around since the 1950s. Even though it is gaining in popularity today, it is not the predominant programming paradigm used in software applications today. Despite the stated benefits of functional programming, there are some downsides of it that can help explain why it is not the mainstream programming paradigm:

  • Lack of imperative data structures. One good example is the lack of hash map which is an important performant dictionary.
  • Functional programming can be slower than optimal Imperative programming for reasons such as data copying due to data immutability.
  • And various other concerns

Some of these reasons help in part explain why 'impure' functional languages like Scala is much more popular today than Haskell. Scala is a general purpose language that has interoperability with Java and has support for both imperative and functional programming paradigms. This establishes a middle ground for programmers new to functional programming.

Guides on Functional Programming

Functional programming can be a very different programming paradigm and it definitely takes time to practice to be an expert at it. To learn more about functional programming, take a look at these amazing guides for a deeper understanding: