jemmons
jemmons

Reputation: 18657

Why do curried functions require external parameter names?

Given this simple currying function:

func foo(x:Int)(y:Int)->String{
  return "\(x) with \(y)"
}

I'd expect to be able to do something like this:

let bar = foo(1)
bar(2) //<- error: Missing argument label 'y:' in call

If I label the call to bar (as in bar(y:2)) everything works fine. But I don't understand why the parameter name is necessary. Is there any way to avoid it?

The obvious thing:

func foo(x:Int)(_ y:Int)->String ...

does not seem to work.

Upvotes: 18

Views: 1812

Answers (5)

David Berry
David Berry

Reputation: 41226

Definitely a bug in the compiler as far as I can tell. Until it's fixed you can get a properly curried version of any function using these functions (note that I've included cases for two and three arguments, extend at your leisure:

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

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

Just use:

curry(addTwoNumbers)(1)(2)

Upvotes: 0

AJ Meyghani
AJ Meyghani

Reputation: 4599

Not the best syntax, but if you want to get around it for now, you can use the following for basic curried functions:

func foo(x:Int) -> Int -> String {
  return {
    return "\(x) with \($0)"
  }
}

Then you can just do:

let bar = foo(1)
bar(2) //-> 1 with 2

Now obviously the problem with this becomes obvious when you want to write a curried function for piping four Ints for example:

func makerAdders(a:Int)(b:Int)(c:Int)(d:Int) {...}

becomes like this:

func add(a:Int) -> Int -> Int -> Int -> Int {
  return { 
    b in return {
      c in return {
        d in return a + b + c + d 
      }
    }
  }
}

The inner closures make it a bit better than using inner functions, but again it defeats the purpose of the nice func add(a:Int)(b:Int)(c:Int)(d:Int) {return a+b+c+d} syntax.

Upvotes: 0

Gabriele Petronella
Gabriele Petronella

Reputation: 108111

It's a bug, you should file a radar at bugreport.apple.com

As a confirmation, if you place an underscore, like this

func foo(x: Int)(_ y: Int) -> String

you get a warning

Extraneous '_' in parameter: 'y' has no keyword argument name

So it explicitly says that y has no external name, but it still requires one when called, which is clearly against the language specification.

Upvotes: 8

fqdn
fqdn

Reputation: 2843

I believe it is a compiler bug, your example should work as described in The Swift Programming Language book where they mention declaring curried functions:

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

addTwoNumbers(4)(5) // Returns 9

https://bugreport.apple.com

good find!

Upvotes: 1

ColinE
ColinE

Reputation: 70142

I am not sure I fully understand your currying. Here is my take on it. I have a function foo as follows:

func foo(x:Int, y:Int) -> String{
  return "\(x) with \(y)"
}

let bar = foo(1, 2) // gives "1 with 2"

I wish to curry this function to 'fix' the value for x, so do so as follows:

func fooCurry(x:Int) -> (Int -> String) {
  func curry(y:Int) -> String {
    return foo(x, y)
  }
  return curry
}

The above returns a new function which can be used as follows:

let curriedFoo = fooCurry(1)
let barWithCurry = curriedFoo(2) // gives "1 with 2"

The function returned by fooCurry has the signature (Int -> String), which means that the parameter does not have an external name.

Upvotes: 0

Related Questions