If this post is helpful for you, consider donating to my patreon. It helps me produce better tutorials, faster. Visit my Patreon.

Become a Patron!

Function Currying in Swift

This post written by Guanshan Liu
Guanshan is an iOS Developer currently working as an iOS Engineer at Alibaba Inc. Before working at Alibaba, Guanshan worked with 2K Games on Civilization Revolution 1 and 2 for iOS. He has a Masters in Software Engineering from the University of York, UK as well as a Bachelors of Engineering in Information Security from Nanjing University of Aeronautics and Astronautics. Find him on twitter, @guanshanliu.
 

Function Currying in Swift

The concept of currying is that instead of accepting multiple arguments, a function accepts only one, and returns a function which acepts the remaining arguments. The returned function will also accept only one argument, and returns another function. This process continues until all arguments are exhausted and we are left only with a single return value.

For example, usually we define a function that returns the sum of two integers as follows:

func add1(x: Int, y: Int) -> Int {
    return x + y
}
add1(1, 2) // Output: 3

We can always transform a function taking multiple arguments into a curried one, by separating the function into a series of function that each takes only one argument. The curried version of add1 is as follows:

func add2(x: Int) -> (Int -> Int) {
    return { y in return x + y }
}
add2(1)(2) // Output: 3

This function has this type specified: Int -> Int -> Int. This may seem a little strange to newcomers to functional programming. Which part is the argument, and which part is the return type?

Here, add2 is taking an Int, and returning a Function which takes another Int, which in turn returns a third Int. You could say it’s something like this: Int -> (Int -> Int), or we could use typealias to make (Int -> Int) more clear:

typealias IntTransformer = (Int -> Int)

Now, any time we see IntTransformer, it’s easier to comprehend that it’s a function that transforms an Int value. With that, we could redfine add2 like this:

func add2Aliased(x: Int) -> IntTransformer {
...

This probably looks a little more familiar, but under the hood this is exactly the same as the add2 function we defined with the data type Int -> Int -> Int. This is just a more familiar looking way to write it.

Calling add2() with just a single argument returns a function that takes another (Int -> Int) function, which means we can store that function in a separate variable if we so choose:

let addTwentyTransformer = add2(20)
addTwentyTransformer(5) // Output: 25

Now, add2(20) is a function that takes one integer and returns the value of that integer plus 20.

The -> operator is defined as associativity right. Instead of writing A -> (B -> (C -> D)), we can simply write A -> B -> C -> D.

Swift also supports another way to define a curried function:

func add3(x: Int)(y: Int) -> Int {
    return x + y
}
add3(1)(y: 2) // Output: 3

This is helpful if you want named parameters, which can sometimes help your code easier to read. It’s also easy to make the syntax the same as add2 and remove the explicit argument name.

func add4(x: Int)(_ y: Int) -> Int {
    return x + y
}
add4(1)(2) // Output: 3

Benefits of Currying

What are the benefits currying provides? Let’s look at the add functions above.

With add1 the regular function, we cannot apply this function until both of its arguments are ready. With the curried add2, we can apply one or two arguments.

Let’s see an example that uses add1 and add2 with mapto transform an array of integers by adding 7 to each.

// Apply map to the array using the two functions
let xs = [1, 2, 3]
let addSeven1 = { add1($0, 7) }
map(xs, addSeven1) // Output: [8, 9, 10]
let addSeven2 = add2(7)
map(xs, addSeven2) // Output: [8, 9, 10]

The curried function add2 is much cleaner in this case.

There is another case when curried functions have obvious advantages. To demonstrate the example, first we define a function (a custom operator) that composes two functions together:

// Define a new operator |> that has left associativity
infix operator |> { associativity left }
func |> <A, B, C>(f: B -> C, g: A -> B) -> A -> C {
    return { x in
        f(g(x))
    }
}

Let’s say we want to transform an array of integers by adding 7 to each element, and then adding 3 again. We could write:

let xs = [1, 2, 3]
 
// Returns a function that adds three to it's only argument
let addThree = add2(3)
 
// Apply addSeven1 to every item in xs
// Then apply addThree to every item in that list
xs.map(addSeven1).map(addThree) // Output: [11, 12, 13]

It first adds 7 to each element in xs, wraps the results into a temporary array, then add 3 to each in the temporary array, and return the last results in a new array. This creates a temporary array that we never need.

By composing the curried functions, addSeven2 and addThree, we can eliminate the creation of the temporary array.

xs.map(addSeven1 |> addThree) // Output: [11, 12, 13]

Builtin Currying Functions in Swift

In the Swift standard library there is a function on the Int type called advancedBy that takes an amount, and returns an Int that has been adjusted by that amount.

extension Int : RandomAccessIndexType {
    func advancedBy(amount: Distance) -> Int
}

It’s simple enough to use this function on an Int and get the advanced value:

5.advancedBy(6) // Output: 11

But because of function currying, we could get the partial application of this function by not specifying the initial value to be advanced:

let add6 = Int.advancedBy(6)
add6(5) // Output: 11
add6(10) // Output: 10

Let’s look at the following example. To insert another string at the end of the given string, we could call the splice function on an instance of String:

var s = "Hello"
s.splice(", world", atIndex: s.endIndex)
// Output: "Hello, world"

Or we can call it on String data type, and pass the String instance as its only argument:

String.splice(&s)("!!!", atIndex: s.endIndex)
s // Output: "Hello, world!!!"

The splice function on a String instance is not a curried function. s.splice("!!!")(atIndex: s.endIndex) will not compile.

The term partial application, is a function that accepts only some of its arguments, and returns another function that takes the rest of arguments. While a curried function takes only one argument.

Don’t confuse partial application with another term called partial function. Partial function is a function that cannot provide a valid result for all its possible inputs. In Objective-C, if we call [[NSString alloc] initWithString:nil], it will compile but throw a NSInvalidArgumentException at runtime. -initWithString: is a partial function, because there is no return value for nil.

Next Steps

Is this all making sense? This can all be quite a chunk of new information to take in if you are new to functional programming in general. For that reason we are preparing a free functional programming course that is in private beta testing right now. If you want to be part of the beta, or just want us to let you know when it’s ready, sign up for the beta here.

Did this tutorial help you?

Support my Patreon

Your support on Patreon allows me to make better tutorials more often.

Follow me on Twitter
Subscribe via RSS

Comment