Diving into Functional Programming

functional programming

Programmers have been writing code for decades now.  Billions of lines, gallons of coffee and countless hours in front of a keyboard.  Over time, patterns and styles have emerged to make the task of building and maintaining code much easier.  This is an ongoing process which has gone through many eras.  From machine code to procedural code to patterns that are widely used today like imperative and Object-Oriented Programming (OOP), programming languages try to follow one or more of these paradigms to help facilitate development.  Lately, one paradigm has been showing up in more and more languages due to many of its useful qualities.

Functional programming is a style of computing that treats a program like the computation of mathematical functions. Like a math equation, all function in this paradigm are deterministic.  This means for any given input, the output will always be the same no matter how many times it is called.  Since functions are such a critical part of functional programming, they are considered first-class functions.  What this means is a function is treated like any other entity in a program such as an object or a number.  They can be assigned to a variable and passed to another function.  That function is called a higher-order function which means it can take a function as an input and/or return a function as an output.  This behavior is used extensively.  In this paradigm functions are said to be pure, meaning there are no side effects from running the function.  What is a side effect?  Anything that changes the state of the application or mutates an object.  It doesn’t matter how you call or interact with the functions as long as the inputs do not change, the output does not change.

This behavior allows functions to be run in parallel since they are by definition, thread-safe.  They also allow environments to safely cache commonly run functions since the same inputs will always produce the same output.

This is great at a lower level, but what advantages are there for a developer to learn functional programming?  My motivation was to learn different ways to solve problems.  With many languages like Java and Python, there is a tendency to write programs in an imperative way using state and mutable data when often times it is unnecessary.  Manipulating a data structure instead of returning a new one has a tendency to cause bugs and hidden behavior.  Functional programming is a way to explicitly say what should happen in a program.  Another reason to learn this program is because many of your favorite languages have implemented aspects of it.  While these languages are not a pure functional language like Haskell, they aim to incorporate some of the great aspects of the paradigm.  Java 8 made a big leap into functional paradigms with first-class and lambda functions.  JavaScript, Groovy, Scala and more offer extensive ways to use and create functions.  It is a great idea to isolate some of these concepts from imperative or OOP ways to developing code to see how powerful they can be.

Some of you may be wondering how purely functional languages handle non-deterministic behavior.  After all, the world isn’t as simple and clean as a carefully constructed math problem.  How does a purely functional language deal with concepts like IO, Randomness and error handling?  All of these concepts produce side effects which break the paradigm and seemingly make pure functional programing impossible.  Like a shrewd lawyer, functional programming has an answer.  While a function cannot cause a side effect, it can create a value to describe a desired side effect that the caller applies. In pseudocode:

The state of the program is given to a function, and when it changes it returns a whole new state, it does not overwrite what currently exists.  A similar concept exists in the Javascript framework React where the previous state is not overwritten but replaced by a new updated state.  In Haskell, side effects are encapsulated in a concept called monads.  This may need to be made into another blog post, as the concept can be complex.  At a high level, monads determine how side effect causing behavior can be used in functions and what rules other functions need to follow using these types.  For example, there is a monad called “Maybe.”  Like Schrödinger’s cat, it is a type that may or may not contain a value. This value cannot be determined until the program is running, and as such any functions using a Maybe monad output, need to be prepared for both cases.

Functional programming aims to make development like evaluating mathematical functions.  This style avoids changing the state of a program and cause unintended consequences.  This is a style to avoid errors due to mutable data and simplifies testing.  It can handle side effects causing behaviors like interacting with memory or IO using functions that describe the side effect, so it can be dealt with transparently.  Functional programming elements are showing up in every major language and it is worth checking them out to augment your code.

< Back to Blogs