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
Swiftui: Pop to Root View When Selected Tab Is Tapped Again
Pass Variables from One Viewcontroller to Another in Swift
How to Create a View-Based Nstableview Purely in Code
Xcode 9 and Xcode 10 Giving Different Results, Even with Same Swift Version
Swiftui iOS 14 Widget Countdown
Draw Scenekit Object Between Two Points
Convert Uiimage to Grayscale Keeping Image Quality
Extension May Not Contain Stored Property But Why Is Static Allowed
Propagate an Optional Through a Function (Or Init) in Swift
Any Way to Iterate a Tuple in Swift
How to Set Collection View's Cell Size via the Auto Layout
Using Function Parameter Names in Swift