Fun with Functions



Today’s article is about doing some fun with Swift functions, like functions returning functions, currying and operators on functions.

Functions basics

In this post we’ll use functions that takes a Int and return a Bool telling if it matches a certain criteria. This kind of functions can then be used with filter to filter an array of integers.

So let’s start with a simple one, a function that tells if a number is positive:

func isPositive(value: Int) -> Bool {
  return value > 0
}

[-4,-2,0,4,7,-8,3].filter(isPositive)
// returns: [4,7,3]

More generic functions

Now what if we want to have a function that returns true if the number is a multiple of N? Sure we could write one function for isEven, one for isMultipleOf3, isMultipleOf4… but where to end?

Of course, a better solution is to have a function that takes that N as a parameter. But then if we write this, filter won’t like it:

func isMultiple(multiple: Int, value: Int) -> Bool {
  return value % multiple == 0
}

[-4,-2,0,4,7,-8,3].filter(isMultiple)
// Error: filter expects Int->Bool and we gave it (Int,Int)->Bool instead
[-4,-2,0,4,7,-8,3].filter(isMultiple(3))
// Error: can't call `isMultiple` with only one parameter, it expects two

Functions returning Functions

So what we really want is a way to generate a new Int -> Bool function (that will fit what filter expects) given a multiplier value. So let’s write exactly that: a function that takes a (multiplier: Int) and returns… another function, of type Int -> Bool.

There is multiple ways to do that, the first being to declare a Int -> Bool function inside our isMultiple function, and return that inner function:

func isMultiple(multiplier: Int) -> (Int -> Bool) {
  func multFunctionToReturn(value: Int) -> Bool {
    return value % multiplier == 0
  }
  return multFunctionToReturn
}

Here the inner function “captures” the multiplier parameter provided by the outer function to generate a tailored function and return it.

But the more common (and compact) way is to use closures instead. In Swift, functions and closures are interchangeable, so let’s directly return a closure of type Int -> Bool:

func isMultiple(multiplier: Int) -> (Int -> Bool) {
  return { (value: Int) -> Bool in
    value % multiplier == 0
  }
}

Currying1

There is actually a third way to achieve that: using currying. Currying is the idea of transforming a function that takes multiple parameters into a function that takes one parameter and returns another function (which in turn takes the next parameter and return a function… until all parameters have been consumed and it returns the final value). This technique allows you to do partial application of a function, which can be very powerful and useful in some cases.

In Swift, we can very easily change a method with multiple parameters into a currying method, by replacing commas separating the parameters with a closing parenthesis immediately followed by a reopening one1. So let’s reuse our very first implementation of isMultiple but transform that into a currying function:

func isMultiple(multiplier: Int)(value: Int) -> Bool {
  return value % multiplier == 0
}

This syntax may be a bit disturbing, so I personally prefer explicitly using a function returning a function (like in the previous paragraph), as in the end this currying form is exactly equivalent to this (which I find more explicit):

func isMultiple(multiplier: Int) -> (value: Int) -> Bool {
  return { value in value % multiplier == 0 }
}

But in the end it’s up to you to use the syntax you prefer.

[EDIT on 01 Feb. 2016]
🚨 A proposition to remove this currying syntax in Swift 3.0 has been accepted since this blog post, so this (x: T)(y: U) syntax will no longer be valid soon. One more reason not to use it and to prefer using (x: T) -> (y: U) instead!

Combining functions

What could be nice next is to combine those filters, to generate a new filter from it. For example, now that we have isPositive and isMultiple, how could we filter every number that are both positive and even?

Of course we could filter twice, like this:

[-4,-2,0,4,7,-8,3].filter(isPositive).filter(isMultiple(2))

But that’s not very efficient since it makes the code loop twice into the array. And moreover, it could also be interesting to have numbers that are either positive or even, and we wouldn’t have a nice syntax for that, but only this:

[-4,-2,0,4,7,-8,3].filter { value in isPositive(value) || isMultiple(2)(value) }

Wouldn’t it be cool instead to generate a new function by combining two Int -> Bool functions? It would indeed feel more natural to write something like this:

[-4,-2,0,4,7,-8,3].filter(isPositive || isMultiple(2))

Well, let’s make that possible!

The && and || operators already exist, so we just need to override them so they supports taking Int -> Bool functions as a parameter:

func || (lhs: Int->Bool, rhs: Int->Bool) -> (Int->Bool) {
  return { (value: Int) -> Bool in
    return lhs(value) || rhs(value)
  }
}

We could also do the same for &&. Let’s use a more compact syntax for this one, using implicit $0 parameters, to vary the examples:

func && (lhs: Int->Bool, rhs: Int->Bool) -> (Int->Bool) {
  return { lhs($0) && rhs($0) }
}

What about also having a way to negate a function, by overloading the prefix ! operator too?

prefix func ! (f: Int->Bool) -> (Int->Bool) {
  return { value in !f(value) }
}

And now we could even write:

[-4,-2,0,4,7,-8,3].filter( !isPositive || isMultiple(3) )
// return [-4,-2,0,-8,3] (non-positive numbers + multiples of 3)

Isn’t that beautiful?

One could even declare those shorthand aliases for negative and odd/even filters:

let isZero = { value in value == 0 }
let isPositiveOrZero = isPositive || isZero
let isNegative = !isPositive && !isZero
let isNegativeOrZero = !isPositive
let isEven = isMultiple(2)
let isOdd = !isEven

And this works like expected, even if those are functions, thanks to our overloading above!

Conclusion

So with those simple tricks, you learned how having functions returning functions can be useful, how we could imagine some operators to combine functions returning Bool the same way we would’ve combined Bool directly, and were introduced to the concept of currying.

There is a lot more fun we could have with function. We could have made those overload of &&,|| and ! generic, so that it would work with any T->Bool functions whatever the type of T is for example. I could even talk about using currying to its full power, go crazy with Functional Programming and all (but a lot of other blogs do that already, so no need for another one here I guess), but I think that’ll be enough for today!

Happy Swifting all!

  1. [EDIT] This syntax using (x:T)(y:U) will be deprecated in Swift 3.0, so you should not use it anymore.  2