4 min read

Swift takes inspiration from functional languages in a lot of its features, and one of those features is currying. The idea behind currying is relatively straightforward, and Apple has already taken the time to explain the basics of it in The Swift Programming Language. Nonetheless, there’s a lot more to currying in Swift than what first meets the eye.

What is currying?

Let’s say we have a function, f, which takes two parameters, a: Int and b: String, and returns a Bool:

func f(a: Int, _ b: String) -> Bool {
    // … do somthing here …
}

Here, we’re taking both a and b simultaneously as parameters to our function, but we don’t have to do it that way! We can just as easily write this function to take just a as a parameter and then return another function that takes b as it’s only parameter and returns the final result:

func f(a: Int) -> ((String) -> Bool) {
    return { b in
        // … do somthing here …
    }
}

(I’ve added a few extra parentheses for clarity, but Swift is actually just fine if you write String -> Bool instead of ((String) -> Bool); the two notations mean exactly the same thing.)

This formulation uses a closure, but you can also use a nested function for the exact same effect:

func f(a: Int) -> ((String) -> Bool) {
    func g(b: String) -> Bool {
        // … do somthing here …
    }
    return g
}

Of course, Swift wouldn’t be Swift without providing a convenient syntax for things like this, so there is even a third way to write the curried version of f, and it’s (usually) preferred over either of the previous two:

func f(a: Int)(_ b: String) -> Bool {
    // … do somthing here …
}

Any of these iterations of our curried function f can be called like this:

let res: Bool = f(1)("hello")

Which should look very similar to the way you would call the original uncurried f:

let res: Bool = f(1, "hello")

Currying isn’t limited to just two parameters either; here’s an example of a partially curried function of five parameters (taking them in groups of two, one, and two):

func weirdAddition(x: Int, use useX: Bool)(_ y: Int)(_ z: Int, use useZ: Bool) -> Int {
    return (useX ? x : 0) + y + (useZ ? z : 0)
}

How is currying used in Swift?

Believe it or not, Swift actually uses currying all over the place, even if you don’t notice it. Probably, the most prominent example is that of instance methods, which are just curried type methods:

// This:
NSColor.blueColor().shadowWithLevel(1/3)
// …is the same as this:
NSColor.shadowWithLevel(NSColor.blueColor())(1/3)

But, there’s a much deeper implication of currying’s availability in Swift: all functions secretly take only one parameter!

How is this possible, you ask? It has to do with how Swift treats tuples. A function that “officially” takes, say, three parameters, actually only takes one parameter that happens to be a three-tuple. This is perhaps most visible when exploited via the higher-order collections method:

func dotProduct(xVec: [Double], _ yVec: [Double]) -> Double {
    // Note that (this particular overload of) the `*` operator
    // has the signature `(Double, Double) -> Double`.
    return zip(xVec, yVec).map(*).reduce(0, combine: +)
}

It would seem that anything you can do with tuples, you can do with a function parameter list and vice versa; in fact, that is almost true. The four features of function parameter lists that don’t carry over directly into tuples are the variadic, inout, defaulted, and @autoclosure parameters. You can, technically, form a variadic, inout, defaulted, or @autoclosure tuple type, but if you try to use it in any context other than as a function’s parameter type, swiftc will give you an error.

What you definitely can do with tuples is use named values, notwithstanding the unfortunate prohibition on single-element tuples in Swift (named or not). Apple provides some information on tuples with named elements in The Swift Programming Language; it also gives an example of one in the same book.

It should be noted that the names given to tuple elements are somewhat ephemeral in that they can very easily be introduced, eliminated, and altered via implicit conversions. This applies regardless of whether the tuple type is that of a standalone value or of a function’s parameter:

// converting names in a function's parameter list
func printBoth(first x: Int, second y: String) {
    print(x, y, separator: ", ")
}
let printTwo: (a: Int, b: String) -> Void = printBoth

// converting names in a standalone tuple type
// (for some reason, Swift dislikes assigning `firstAndSecond`
// directly to `aAndB`, but going through `nameless` is fine)
let firstAndSecond: (first: Int, second: String) = (first: 1, second: "hello")
let nameless: (Int, String) = firstAndSecond
let aAndB: (a: Int, b: String) = nameless

Currying, with its connection to tuples, is a very powerful feature of Swift. Use it wherever it seems helpful, and the language will be more than happy to oblige.

About the author

Alexander Altman is a functional programming enthusiast who enjoys the mathematical and ergonomic aspects of programming language design. He’s been working with Swift since the language’s first public release, and he is one of the core contributors to the TypeLift project.

LEAVE A REPLY

Please enter your comment!
Please enter your name here