Curry is a very flexible feature in Swift. In the simplest language, Curry is a mechanism for generating methods from methods. It makes our method definitions more dynamic, and even the built-in methods can be integrated through Curry’s method.

Following up on our previous article, which introduced the basics of Curry, we’ll extend the scope of the curry mechanism.

For basic curry usage, see our previous post:

The magic of Currying

Curry works on the system’s built-in methods

In the previous article, we showed you how to curry our own methods, but what about built-in methods, or methods defined in other third-party libraries? How do we apply Curry to them?

We can create an example where we define a multiple method for NSNumber:

extension NSNumber {
    
    class func multiple(left: Int, right:Int) -> Int {
    
        return left * right
        
    }
    
}Copy the code

How can it support the Curry feature without changing the definition of this method?

We can define a function called curry:

func curry(function: (Int,Int) -> Int) -> (Int -> (Int -> Int)){
    
}Copy the code

Curry accepts arguments of type (Int,Int) -> Int. This takes two ints and returns an Int. The multiple function type we defined in the NSNumber extension. We can pass number.multiple as an argument to this method.

(Int -> (Int -> Int)) this takes an Int and returns an Int -> Int. The return value, of course, is a function. The return function is a function that takes 1 Int and returns a value of type Int.

The curry function converts a function passed to it into another function that bears currying.

Let’s see how it works:

func curry(function: (Int,Int) -> Int) -> (Int -> (Int -> Int)){
    
    return { a in
        
        { b in
            return function(a,b)
        }
        
    }
    
}Copy the code

The return statement first returns an outer closure:

This closure returns a value of type (Int -> (Int -> Int)), and the first closure contains another closure:

{ a in
	//...
}Copy the code

Because the return type of our Curry function is (Int -> (Int -> Int)), it will also return another function, so we need the next closure, which corresponds to the second half of the (Int -> Int) in (Int -> Int).

{ b in
	return function(a,b)
}Copy the code

The innermost closure then calls function, passing in parameters A and b to complete the calculation of the function. Function corresponds to the nsNumber.multiple method we define.

Let’s look at calling methods:

let curriedMultiple = curry(NSNumber.multiple)

curriedMultiple(3)(2)Copy the code

The Curry function converts the nsNumber. multiple method to the curriedMultiple function, which supports Curry’s features, so it can be called as curriedMultiple(3)(2).

This feature is flexible.

A more general approach

The curry function can convert the NSNumber multiple method into a function that supports currying, but the curry function is limited by argument types and can only convert methods that take ints.

We can also use Swift’s generics mechanism to make this method more adaptable:

func curry(function: (A,B) -> C) -> (A -> (B -> C)){
    
    return { a in
        
        { b in
            return function(a,b)
        }
        
    }
    
}Copy the code

With generics, we change the concrete parameter types into the form of type parameters A,B,C. This way, our curry method can take currying of any method that takes two arguments.

For example, these two methods are defined:

extension NSNumber {

    class func multiple(left: Int, right:Int) -> Int {
    
        return left * right
        
    }

    class func add(left:Double, right:Double) -> Double {
        
        return left + right
        
    }
    
}Copy the code

You can use the Curry function to manipulate such a method:

Curry (nsNumber.multiple)(3)(3) // 9 Curry (nsNumber.add)(3.0)(3.0) // 6.0Copy the code

Make the use of the Curry function more generic with generics.

So there’s another problem, the number of arguments, if we have three or more arguments.

Someone has already solved this problem for us, the Curry third-party library, whose Guthub home page:

Github.com/thoughtbot/…

This library is implemented as described in this article, and it supports any number of parameters.

This site articles are original content, if you need to reprint, please indicate the source, thank you.