Curry Function in Swift

Curry Function in Swift

You can achieve this pretty easily with closures:

/// Takes a binary function and returns a curried version
func curry<A,B,C>(f: (A, B) -> C) -> A -> B -> C {
return { a in { b in f(a, b) } }
}

curry(+)(5)(6) // => 11

let add: Int -> Int -> Int = curry(+)
add(5)(6) // => 11

It would be really nice to be able to do the same thing for functions that take 3, 4 or more arguments, but without duplicating the implementation. The signature of such a function might start something like:

/// Take a function accepting N arguments and return a curried version
func curry<T>(args: T...) -> /* ? */

What would the return type be? It would change based on the input to the function. This definitely isn't possible in Swift at the moment, and I don't think it would be possible at all without some kind of macro system. But even with macros I don't think the compiler would be satisfied unless it knew the length of the list at compile-time.

Having said that, it's really straight-forward to manually overload the currying function with a version that accepts 3, 4, 5 or more parameters:

func curry<A,B,C,D>(f: (A, B, C) -> D) -> A -> B -> C -> D {
return { a in { b in { c in f(a,b,c) } } }
}

func curry<A,B,C,D,E>(f: (A, B, C, D) -> E) -> A -> B -> C -> D -> E {
return { a in { b in { c in { d in f(a,b,c,d) } } } }
}

// etc.

Uncurrying curried Function in Swift

Your uncurry function can do just that, uncurry curried functions:

let currableSum = curry(sum)
let uncurriedSum = uncurry(currableSum)

let add100 = currableSum(100)
print(add100(23)) // => 123

print(uncurriedSum(2, 2)) // => 4

The issue is that you're mistaking uncurrying for unapplying. Once you've partially or fully applied a curried function (or any function, for that matter), there's no mechanism to go back, to get the original function that produced the result.

uncurry(add100) // ❌ can't "unapply" a partially applied function

Imagine if that were the case. Every integer, string, and other value would have to remember a history of what functions caused it. I can't think of a single use case for that. For one, it would require dynamic typing (or forced compile-time casting in a static language like Swift), because you can't predict the signature of an arbitrary function that produces a given result.

Swift: Benefits of Curry Function

The problem is that the example given isn't an example of currying exactly. That's why you don't see any value in it.

This is a better example of currying:

class MyHelloWorldClass {
//Function that takes two arguments
func concatenateStrings(string1: String, string2: String) {
return "\(string1)\(string2)"
}
//Curried version of concatenateStrings that takes one argument.
func helloWithName(name: String) -> String {
return concatenateStrings("hello, ", name)
}
}

This is a better example of how function variables are curried functions in Swift: http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/

Implementing a curried map function in Swift

First, a warning: many techniques that are commonly used in FP languages, including currying, are completely possible in Swift, but extremely inconvenient. They often become so wordy that they lose their value. The early versions of Swift had currying built-in, and it was intentionally removed because it causes a lot of headaches in Swift. This does not mean that higher-order functions are a problem, or functions that return functions. And even currying itself can be useful sometimes. But as a rule it isn't in Swift.

The point of @escaping is that the closure may "escape" the current context, and therefore there are different memory management concerns. This changes whether self. is required in the closures. To resolve it, you need to tell the system that you are aware of this, and warn the caller, by adding @escaping.

func map<A,B>(_ f: @escaping (A) -> B) -> (([A]) -> [B]) {

In this case, the closure f outlives the call to map(), and so anything that f captures may have a lifespan longer than the caller might otherwise expect, and potentially could lead to strong reference cycles. Most FP-friendly languages have garbage collection that can handle cycles. Swift uses ARC for automatic memory management. It's more deterministic and has more predictable performance, but cannot handle cycles, so certain things that are natural in FP-friendly languages don't translate easily.

See Escaping Closures in the Swift Programming Language for full details.

As a rule, Swift composes with types (especially structs) by using protocols and extensions, rather than by composing functions, objects, or algebraic types as you might in other languages.

Typecase regular Swift function to Curry Function

You don't typecast it, you return nested closures that capture each parameter in turn:

func add(x: Int, y: Int) -> Int {
return x + y
}

func curry<T1, T2, T3>(f: (T1, T2) -> T3) -> T1 -> T2 -> T3 {
return {
(t1: T1) -> T2 -> T3 in

return {
(t2: T2) -> T3 in

return f(t1, t2)
}
}
}

let curriedAdd = curry(add)
let add3 = curriedAdd(3)
println(add3(5))
// 8

This is more succinct:

func curry<T1, T2, T3>(f: (T1, T2) -> T3) -> T1 -> T2 -> T3 {
return { t1 in { t2 in f(t1, t2) } }
}

I thought it would be fun to write a curry maker; here it is - if anyone knows how to make one of these that generates an actual function that would be amazing:

func curryRecipe(n: Int) -> String {
let types = join(", ", map(1...n, { "T\($0)" }))
let returnType = join(" -> ", map(1...n, { "T\($0)" }))
let closures = join(" in ", map(1...n, { "{ t\($0)" }))
let braces = join(" ", Array(count: n, repeatedValue: "}"))
return "func curry<\(types), R>(f: (\(types)) -> R) -> \(returnType) -> R {\r" +
" return \(closures) in f(\(types.lowercaseString)) \(braces)\r}"
}

println(curryRecipe(15))

Output:

func curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R>(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) -> R) -> T1 -> T2 -> T3 -> T4 -> T5 -> T6 -> T7 -> T8 -> T9 -> T10 -> T11 -> T12 -> T13 -> T14 -> T15 -> R {
return { t1 in { t2 in { t3 in { t4 in { t5 in { t6 in { t7 in { t8 in { t9 in { t10 in { t11 in { t12 in { t13 in { t14 in { t15 in f(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) } } } } } } } } } } } } } } }
}

How to understand the currying in Swift?

-> operator is right associative. So we can rewrite curry function like this.

func curry<A, B, C>(f: @escaping (A, B) -> C) -> ((A) -> ((B) -> C)) {
return { x in { y in f(x, y) } }
}

Every ( matches with { inside return part.

EDIT: Further explanation

curry function takes a non-curried two argument function and makes it curried. For example we have:

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

Now we can use this function like this:

let result = sum(3, 6)

But if we make it curried

let curriedSum = curry(sum)

Now we can use it like this:

let result = curriedSum(3)(6)

At first this seems unnecessary and complex. But think about what next expression does.

let sumWith3 = curriedSum(3)

This produces a new function that takes an Int sums it with 3. Now here we created a new function from another function. Now we can use it like any other function.

Currying is common paradigm in functional programming. In fact in Haskell (another functional programming language) every function is curried by default.

currying in Swift, new declaration syntax in future?

only the declaration syntax will be removed e.g. func(a: Int)(b:Int) -> Int

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

is equivalent to:

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

Cannot translate Swift 2.2 currying to future Swift format

The inner curly braces are wrong, it should be:

func handleDownload2(iCount:Int) -> (NSData?, NSError?) -> Void {
return { (data: NSData?, error: NSError?) -> Void in
// received image
print(iCount)
print(data!.length)
}
}

What is a generalized uncurry function in Scheme, for a curry function of n parameter?

A generic uncurry can be written to call a function, f, with arguments, t, one at a time -

(define ((uncurry f) . t)
(if (null? t)
f
(apply (uncurry (f (car t)))
(cdr t))))

Using it on (curry +) will not work because + is a variadic function. However, for functions of known arity, it works just fine -

(define (plus a b c)
(+ a b c))

((uncurry (curry plus)) 1 2 3) ; 6

If you don't supply all three arguments, the "remainder" of the curried function will be returned -

(((uncurry (curry plus)) 1 2) 3)     ; 6
((((uncurry (curry plus)) 1) 2) 3) ; 6
(((((uncurry (curry plus))) 1) 2) 3) ; 6

Subsequent calls to uncurry could be used if additional arguments need to be supplied at a later time -

((uncurry ((uncurry (curry plus)) 1)) 2 3) ; 6

However, if you try to apply too many arguments, a run time error will be raised -

((uncurry (curry plus)) 1 2 3 4)     ; error, expected procedure; 6 given

Is there a way to perform a generalized uncurry function on curried, variadic functions? That was what the question was referring to with "generalized", needs to be able to work on a variable number of arguments.

I recommend you see molbdnilo's comment on your question. You cannot effectively curry a variadic function like + because currying is the abstraction of arity. To put this another way, if + can take 0 to infinite arguments, how many applied arguments should (curry +) take before it returns a sum rather than a function?

Maybe you are looking for partial application?

(define ((partial f . a) . b)
(apply f (append a b)))
((partial + 1 2)) ; 3
((partial + 1) 2) ; 3
((partial +) 1 2) ; 3


Related Topics



Leave a reply



Submit