Use Pipelines to understand Functional Programming

Use Pipelines to understand Functional Programming

About this Series
In this article, you will learn the basic philosophy behind functional programming.

However, there are different ways of looking at it. Each article in this series will explain it differently and will use a different programming language to do so.

Series overview:

  1. Why Functional Programming

  2. Pure Functions (in JavaScript)

  3. Pipelines (in Python) <- You are here

  4. Lambda Functions (in Java)w


Today we will use Python to discuss

Pipelines.

Functional programming transforms data by sending it through pipelines.

As a "pipeline" we describe joined functions that are being applied one after another.

def winnerTotal(data):
  return sumWinners(keepWinners(normalize(data)))

Read this function from right to left: First, we map data into a normalized form. Then we filter out the winners and finally, we sum them up.

We don't have to implement the necessary loops ourselves. We instead use the built-in functions map, filter and sum.

map takes another function and applies it to each value.

# Assume we defined addMissingFields.

def normalize(data):
  return map(addMissingFields,data)

input = [{"name":"John"},{"won":5},{"name":"Julia","won":2}]
normalizedData = normalize(input)
# {"name":"John", "won":0}, <-- we added the missing field "won"
# {"name": None,  "won":5}, <-- we added the missing field "name"
# {"name":"Julia","won":2}

filter takes a condition and returns all values that meet the condition.

# Assume we defined isWinner

def keepWinners(data):
  return filter(isWinner,data)

# We use normalizedData from the last example

winners = keepWinners(normalizedData)
# {"name":None,"won":5}, {"name":"Julia","won":2}

sum returns the sum of all elements.

# Assume we defined getTimesWon

def getWinningTimes(data):
  return map(getTimesWon,winner)

def sumWinners(data):
  return sum(getWinningTimes(data))

# We use winners from the last example

getWinningTimes(winners)
# 5, 2
sumWinners(winners)
# 7

Combining all functions:

def winnerTotal(data):
  step1 = map(addMissingFields,data)
  step2 = filter(isWinner,step1)
  step3 = map(getTimesWon,step2)
  return sum(step3)

We have now built a pipeline that passes the data through. We can use pipelines to build up our program.

And that is what functional programming is all about.

Benefits

Using pipelines lets us write algorithms on a higher level. Instead of describing How something is implemented, we say What needs to be done. The resulting code will loop over the elements just once.

All programming languages nowadays come with a lot of libraries to support this programming style. If you want to see what Python has to offer in that regard, you can check out the two libraries itertools and functools.

If you enjoyed this post and would like to read more, you can check out the book Functional Python Programming by Steven F. Lott. Feel free to also subscribe. Follow me on my journey explaining functional programming from different angles and using different programming languages.


Advanced: Joining pipelines

If you already feel comfortable using pipelines, let's go a step further and see how we can split and merge them. For splitting we just create a variable.

allApples = map(getApples,data)

greenApples = filter(isGreen,allApples)
redApples = filter(isRed,allApples)

We now have two pipelines: one containing green apples and one for red apples.

But how do we join them?
It depends on what we want to achieve. We can join them in parallel (always taking one green and one red apple) or in sequence (first all green apples then all red ones).

For joining them in parallel, we can use the built-in function zip.

applePairs = zip(greenApples,redApples)
# ("GreenApple1","RedApple1"), ("GreenApple2","RedApple2")

But what about joining them in sequence? You might already have guessed the answer: Convert them to lists and then join them together.

greenOrRedApples = list(greenApples) + list(redApples)

Now comes the trick question: What happens if we have infinite apples?

def infiniteElements(element):
    while True:
        yield element

for i in infiniteElements("Red Apple"):
  print i
# "Red Apple" "Red Apple" "Red Apple"...

How would we join infinite red and green apples together? I'd love to read your answers.