Cheat Sheet

Functional Programming For Dummies Cheat Sheet

From Functional Programming For Dummies

By John Paul Mueller

Using functional programming techniques can make you incredibly efficient when solving certain problems or when you need to make full use of multiprocessing techniques to ensure that you get maximum benefit from each processor (or core). The functional programming paradigm supports the concept of pure languages (such as Haskell, which uses only functional techniques) and impure languages (such as Python, which actually supports multiple programming paradigms). In addition, functional programming has a strong math basis: every line of code is actually an expression, not a procedure, as in many other paradigms. This cheat sheet helps you understand these differences from other paradigms to enhance your functional programming experience.

The 4 Common Python Programming Paradigms

Python is an impure functional programming language, which means that it supports other programming paradigms. Depending on your perspective, the support of other paradigms can be a plus or a minus. Using an impure language means that you won’t gain full benefit from using functional programming techniques and that some techniques may not even be available. However, an impure language also enables you to solve some problems in an understandable manner that could look a bit convoluted when using functional programming techniques. With these pros and cons in mind, here are the essential four Python programming paradigms, also called coding styles:

  • Functional: Every statement is a kind of math equation. This style lends itself well to use in parallel processing activities. Academics and data scientists tend to use this coding style regularly. However, nothing is stopping you from using it even if you don’t fall into one of these groups.
  • Imperative: Computations occur as changes to program state. This style is most used for manipulating data structures. Scientists of all sorts rely on this programming style because it demonstrates processes so clearly.
  • Object-oriented: This is the style commonly used with other languages to simplify the coding environment using objects to model the real world. Python doesn’t fully implement this coding style because it doesn’t support features like data hiding, but you can still use this approach to a significant degree. This is the style that most developers use, but other groups can use it when creating more complicated applications.
  • Procedural: Most people begin learning a language using procedural code, through which tasks proceed a step at a time. This style is most used for iteration, sequencing, selection, and modularization. It’s the simplest form of coding you can use. Nonprogrammers love this style because it’s the least complicated way to achieve smaller, experimental tasks.

Essential Functional Programming Paradigm Features

The functional programming paradigm doesn’t actually have an implementation, but it does describe features that a language implementation would have. The following list gives you an idea of which features to look for in a language that supports the functional programming paradigm. The more of these features that a language supports, the purer the implementation.

  • Lambda calculus support: The basis of functional programming is lambda calculus, which is actually a math abstraction. Every time you create and use a lambda function, you’re likely using functional programming techniques (in an impure way, at least).
  • First-class and higher-order functions: First-class and higher-order functions both allow you to provide a function as an input, as you would when using a higher-order function in calculus.
  • Pure functions: A pure function has no side effects. When working with a pure function, you can:
    • Remove the function if no other functions rely on its output
    • Obtain the same results every time you call the function with a given set of inputs
    • Reverse the order of calls to different functions without any change to application functionality
    • Process the function calls in parallel without any consequence
    • Evaluate the function calls in any order, assuming that the entire language doesn’t allow side effects
  • Recursion: Functional language implementations rely on recursion to implement looping. In general, recursion works differently in functional languages because no change occurs in application state.
  • Referential transparency: The value of a variable never changes in a functional language implementation because functional languages lack an assignment operator.

Pioneers of Math Automation

Math wasn’t always automated, which may seem like a surprise in the modern world. People like Alonzo Church, Haskell Curry, Kurt Gödel, Emil Post, and Alan Turing had to create a definition for algorithms. Before anyone could build a computer, someone had to come up with a definition of what it means to compute, which seems obvious now, but wasn’t at all obvious at the time. The following list tells you something because each of the people listed came up with their own definition of what it means to compute and each of these definitions actually has a place in the modern world.

Commonly Used List Functions

Developers tend to consider lists and arrays to be the same sort of structure, but they’re different. The main difference comes in how arrays and lists store the data. An array always stores data in sequential memory locations, which gives an array faster access times in some situations but also slows the creation of arrays. In addition, because an array must appear in sequential memory, arrays are often hard to update, and some languages don’t allow you to modify arrays in the same ways as you can lists.

A list stores data using a linked data structure, and a list element consists of the data value and one or two pointers. Lists take more memory because you must now allocate memory for pointers to the next data location (and the previous location as well in doubly-linked lists, the kind used by most languages today). Lists are often faster to create and add data to because of the linking mechanism, but they provide slower read access than arrays.

However, interacting with lists has some similarities to arrays. With this in mind, the following list shows commonly used Haskell list functions:

  • head a: Shows the value at index 0, which is 1 in this case.
  • tail a: Shows the remainder of the list after index 0, which is [2,3,4,5,6] in this case.
  • init a: Shows everything except the last element of the list, which is [1,2,3,4,5] in this case.
  • last a: Shows just the last element in the list, which is 6 in this case.
  • take 3 a: Requires the number of elements you want to see as input and then shows that number from the beginning of the list, which is [1,2,3] in this case.
  • drop 3 a: Requires the number of elements you don’t want to see as input and then shows the remainder of the list after dropping the required elements, which is [4,5,6] in this case.
  • length a: Returns the number of elements in the list, which is 6 in this case.
  • null a: Determines whether the list is empty and returns a Boolean result, which is False in this case.
  • minimum a: Determines the smallest element of a list and returns it, which is 1 in this case.
  • maximum a: Determines the largest element of a list and returns it, which is 6 in this case.
  • sum a: Adds the numbers of the list together, which is 21 in this case.
  • product a: Multiplies the numbers of the list together, which is 720 in this case.

Python doesn’t provide lists; it uses arrays instead. However, as with Haskell, you can perform certain operations with arrays that look much like their list counterparts. Here is a similar list of commonly used Python array functions:

  • a[0]: Obtains the head of the list, which is 1 in this case.
  • a[1:]: Obtains the tail of the list, which is [2,3,4,5,6] in this case.
  • a[:-1]: Obtains all but the last element, which is [1,2,3,4,5] in this case.
  • a[:-1]: Obtains just the last element, which is 6 in this case.
  • a[:-3]: Performs the same as take 3 a in Haskell.
  • a[-3:]: Performs the same as drop 3 a in Haskell.
  • len(a): Returns the number of elements in a list.
  • not a: Checks for an empty list. This check is a different result from a is None, which checks for an actual null value — a not being defined.
  • min(a): Returns the smallest list element.
  • max(a): Returns the largest list element.
  • sum(a): Adds the number of the list together.