Currying in Swift


Programming is an art. It’s understanding reality and making models of our understanding. It’s about proposing solutions to real world problems, by getting each interacting part of it and they way they do. So, when we talk about paradigms, we’re talking about the basis of theory that we take to think situations. Paradigms has been around for years, proposing ways of thinking and letting us focus straight on the problem that matters to us, rather than in the theory context.

With Swift, as with other modern programming languages as Scala for example, the paradigmatic focus has move from straight (or almost straight) OO thinking to a more functional paradigm thinking. And I’m using the word “more” because modern languages does not propose a fully pure paradigmatic approach,such as Haskell did, but a mixture of concepts and ideas from many approaches. It give us new tools to think problems in new ways, narrowing our limits.

I’d like to talk about one of that concepts, and thats currying. Currying a function (also known as “partially applying a function”) is a really simple concept inherited from the basis of FP, and that is math. The idea is to take a function that takes many arguments and “fix” a value on one of them. The result you’ll get from this process is a new function with, of course, one less argument.

Now you might be thinking “How is this useful?”. The thing is that curried functions are really useful in a functional environment where you don’t think about code imperatively. It’s useful if you are thinking your solution in terms of functional programming, not imperative programming. So, to really understand and follow up the idea, you have to think about declaring your code to achieve something, not to tell it what to do. When using a curried function, you don’t have to think about managing variables and passing them through your functions. Mathematically speaking, your function domain is narrow and safe.

The Cans and Can’ts about Currying in Swift


unfortunately, for those who come from a hard background in Haskell, functions in Swift are not high-ordered by default. What do I mean? In Haskell, every single function takes exactly one argument. So, for working with more than one argument per function (a completely normal scenario), you count on currying high-order functions to get more specific ones. MAP, FILTER, among others are examples of basic but really powerful high-order functions in Haskell.

But Swift is not Haskell. So, we can think in our situations in terms of closures. Closures let us define and return a function. So, by defining a function that takes an argument and encapsulates it into a close, we can return that close in order to call it later and do whatever we want with it.

So, we can approach currying as the following:

func addTwoIntsCurried(a: Int) -> (Int -> Int) {
return {b in a + b}
}

So here we’re writing down our bare concept. Our function takes an Int, creates a closure (where our first parameter is encapsulated, because that’s the definition of closure vs a lambda expression) and returns this “function” that takes another Int and returns a final Int with these numbers addition.

But here’s the thing. Swift already gives us some syntax sugar that comes in handy when you need to declare a curried function.

func addTwoIntsCurried(a: Int)(b: Int) -> Int {
return a + b
}

just by declaring a parameters between separated parenthesis and not just in one big parenthesis, we are saying Swift that we want to pass the function an argument and get a function that encapsulates it.

Now, if you run the code I’ve just written up here and call it, let’s say, this way

addTwoIntsCurried(3)(5)

You’ll see that it gives us an error.

We’re still on β!

And that’s because this currying syntax of Swift presents a bug when it comes to anonymous parameters. When you call the result of a curried function, you have to declare the argument’s name. Even if you declare an empty name for the argument, you’ll still get it. You can follow a stackoverflow question about it here.

I hope it helps! For any questions, contact me on twitter.

cheers!