Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Curry Function in Swift

Tags:

swift

currying

I want to make a function that return a curry function like below

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

addTwoNumbers(4)(b: 6) // Result: 10

var add4 = addTwoNumbers(4)
add4(b: 10) // returns 14     

What is the return type of such function and how can I generate a function like this using a function that take Variadic parameters.

func generateCurry(.../*Variadic parameters*/) -> .../*curry function type*/ {
  return ...//curry function
}

I want a generic solution and not take only Int as arguments in the parmeter of the generateCurry function

let curried = curry(func(a, b, c) {
  print(a + b + c)
})
curried(1)(2)(3) //prints 6
like image 297
Encore PTL Avatar asked Jun 08 '14 14:06

Encore PTL


People also ask

What is currying FP?

Currying is the transformation of a function with multiple arguments into a sequence of single-argument functions. That means converting a function like this f(a, b, c, ...) into a function like this f(a)(b)(c)... . If you know Python's functools. partial , then this is very similar to it.

Why currying is useful in Scala?

Advantages of Currying Function in Scala One benefit is that Scala currying makes creating anonymous functions easier. Scala Currying also makes it easier to pass around a function as a first-class object. You can keep applying parameters when you find them.

What is currying in Lambda?

Currying is a concept from lambda calculus, but don't let that freak you out — it's quite simple to implement. Currying is a function that takes one argument at a time and returns a new function expecting the next argument.

Is currying supported in scheme?

It is possible to generate curried functions in Scheme. The function curry2 generates a curried version of a function, which accepts two parameters. The curried version takes one parameter at a time. Similarly, curry3 generates a curried version of a function that takes three parameters.


2 Answers

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.
like image 131
Adam Sharp Avatar answered Mar 22 '23 23:03

Adam Sharp


I'm not sure this is actually going to be possible in the same way it is inside of languages like Python.

The core problem I see to having a single generic solution is the strong typing of the closures/funcs you want to accept.

You could fairly easily create a curry function that worked on a specific or common function signature, but as far as a general purpose curry I don't see a way for it to work. The issue is more than about the types of the arguments (as mentioned in comments) but also with the number of them.

I've written up a simple example of how you could implement a curry function. It works, but I don't see a sane way to have a truly generic one like you can in more loosely typed languages.

func add(a1: Int, a2: Int) -> Int {
    return a1 + a2
}

func curry(argument: Int, block: (Int, Int) -> Int) -> Int -> Int{
    func curried(arg: Int) -> Int {
        return block(argument, arg)
    }

    return curried
}

curry(5, add)(6)
like image 26
Bryan McLemore Avatar answered Mar 22 '23 22:03

Bryan McLemore