Using Functional Programming on Swift

Franco Consoni
Spark Digital Community
6 min readJun 28, 2018

In this article, I’m going to try to show in the briefest way possible how to respect the building blocks of functional programming, a paradigm that, through hours of research, I found out it is not fully being taken advantage of.

Swift is a functional-object hybrid, thus it gives us support to apply functional programming, be it type inference or flexible function management.

Functional programming

A quick review of the paradigm:

  • A function is a transformation, that takes one (or several) parameter, and returns a value.
  • A function is also a first-class citizen of the paradigm, meaning that it is a value that can be passed as a parameter to another function, get it as a result, or even store it.
  • Basing us in Currying, we can give a function less parameters than it is expecting, so it will give us back a function expecting the missing parameters. This concept is called Partial Application.
  • We can also Compose functions between each other, like in the math world, as long as the first functions’s output matches the second function’s input.
  • We can also pass functions as other function’s parameters. The functions that receive another functions as parameters are called Higher Order Functions.
  • All this couldn’t be possible, without a context that supports immutability, which means that our functions don’t change our data, but give us copies, resulting of applying the function to the original data. Every time we call the function with a certain value, the expected result is the same.

These concepts are the pillars of the paradigm and combining them grants us great flexibility, higher percentage of code reusability and it lets us build way more declarative components.

In Swift

Now, how can we apply these concepts in a hybrid language like Swift, focusing in the functional part of it?

Function and First-Class Citizen

Before anything we define the ‘add’ function:

func add(number: Int, otherNumber: Int) -> Int {
return number + otherNumber
}

Its type is:

add :: (Int, Int) -> Int

The paradigm allows us to store this function, in this case, in a constant:

let storedAdd : (Int, Int) -> Int = add

Or it can also be directly defined like this:

let add = { (num: Int, otherNum: Int) in num + otherNum }

The return value is implicit and the type is inferred automatically.

Both declarations are equivalent so its use is up to preference and context.

With our function defined, lets suppose that we want to add 5 to several numbers:

let foo = add(5,1)let bar = add(5,5)let bla = add(5,100)

Do you see the problem here? We repeat the same action in each case, which is adding 5. What if we want to do this 10 more times? Boilerplate-code. What if we want to make a change? What if instead of adding 5 we want to add 20?Copy-Paste is not an option. So this is where the functional paradigm comes into play.

Partial application and Currying

To apply a function partially it first needs to be curried.

What does it mean for it to be curried? It means that it can be expressed as a sequence of functions that take a single parameter and return a function that expects the next one.

Right now in Swift there is no mechanism by default that does this, but we can build it.

How?

Fairly easy, by doing what Currying defines: make functions that takes one parameter, and returns another function that are waiting the next.

Going back to our function, let's redefine it to support this definition:

let add = {
(a: Int) in {
(b: Int) in a + b
}
}

The type of the function now is:

add :: Int -> (Int -> Int)

This is a function that takes an Int as parameter and returns another function that receives an Int as parameter and returns another Int.

Is it magic? No.

The brackets are just a way of showing that we achieved what we wanted. We got the curried version of our add function!

But now, is it always necessary for our functions to be defined in this way for them to be curried?

The answer is no, we can define a generic higher order function to do this work for us.

Higher Order

A Higher Order Function is no more than a function that receives another function as a parameter. In this case we want to generalize currying:

func curry<A,B,C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> (C) {
return { a in { b in f(a,b) } }
}

The @escaping annotation allows to retain the function ‘f’ to be executed later.

The type is clear, it works the same way as the previous example but at a generic level: now, we can currify any function that receives two parameter of types A and B, and return a value of type C.

Note that we get a function that takes one parameter, and returns another function, that takes one parameter, and so.

Now, applying our currified function we get:

let curriedAdd = curry(add)

The types of both functions are:

add :: (Int, Int) -> Int
curriedAdd :: Int -> Int -> Int

And we can apply these functions:

let a = add(1, 2) // 3let b = curriedAdd(1)(2) // 3

Finally we can partially apply this add:

let plusFive = curriedAdd(5)
plusFive :: Int -> Int

So:

let foo’ = plusFive(1) //result: 6let bar’ = plusFive(5) //result: 10let bla’ = plusFive(100) //result: 105

With some simple function logic we eliminated the repeated code.

Composition

Like we’ve said before we can compose functions as long as they ‘fit’.

If we define a function that gives us the product of two integers:

let product = { (a: Int, b: Int) in a * b }

And we want to get the double of a number, any number, we already saw we need to curry to apply partially:

let doubleOf = curry(product)(2)
doubleOf :: Int -> Int

Now we want the next of the double of a number. In the traditional way we would do:

let nextFromDoubleTraditionally = { (a: Int) in 
plusOne(doubleOf(a))
}

This is annoying because of the brackets and the block syntax. This can be fixed by using composition.

No beating around the bush, one definition, in operator format for better reading:

infix operator >> : AdditionPrecedencefunc >> <T,U,V>(_ f: @escaping (T) -> U, _ g: @escaping (U) -> V) -> (T) -> V {return { g( f($0) ) }}

So the whole original problem is reduced to:

let nextFromDouble = doubleOf >> plusOne

Magic.

Why does this work? Look the types:

doubleOf :: Int -> Int
plusOne :: Int -> Int

The return value type of ‘doubleOf’’ is same as the entry value type of ‘plusOne’. So when we pass an Int value to this composed function, it just fits.

Now we have functions that expects a value and returns another independently of what it does on the inside.

Let’s go further.

Imagine we want to get the quadruple of a number using ‘doubleOf’’.

let quadOf = doubleOf >> doubleOf

Trivial example, but it shows how we can reuse our functions when building new functions, in a very natural way, almost like piling up bricks.

It also helps the reading and makes it easy to see the path the data takes through the transformations.

I invite you to read more about this paradigm, and how to use it in your projects. It’s a path without return.

Note: the composition function that we made here reads from left to right, like a chain of methods. But for better read, and to make it similar to Haskell, we can make a composition that reads from right to left. Here’s an example.

--

--