Почему для карри-функций требуются имена внешних параметров?
Учитывая эту простую функцию каррирования:
func foo(x:Int)(y:Int)->String{
return "\(x) with \(y)"
}
Я ожидаю, что смогу сделать что-то вроде этого:
let bar = foo(1)
bar(2) //<- error: Missing argument label 'y:' in call
Если я отмечаю вызов bar
(как в bar(y:2)
), все работает нормально. Но я не понимаю, почему имя параметра необходимо. Есть ли способ избежать этого?
Очевидная вещь:
func foo(x:Int)(_ y:Int)->String ...
похоже, не работает.
Ответы
Ответ 1
Это ошибка, вы должны подать радар в bugreport.apple.com
В качестве подтверждения, если вы разместите символ подчеркивания, например
func foo(x: Int)(_ y: Int) -> String
вы получите предупреждение
Посторонний '_' в параметре: 'y' не имеет имени аргумента ключевого слова
Поэтому он явно говорит, что y
не имеет внешнего имени, но он все еще требует вызова при вызове, что явно противоречит спецификации языка.
Ответ 2
Я считаю, что это ошибка компилятора, ваш пример должен работать так, как описано в книге Swift Programming Language, где упоминается объявление карриных функций:
func addTwoNumbers(a: Int)(b: Int) -> Int {
return a + b
}
addTwoNumbers(4)(5) // Returns 9
https://bugreport.apple.com
хорошая находка!
Ответ 3
Я не уверен, что полностью понимаю твою карри. Вот мое занятие. У меня есть функция foo следующим образом:
func foo(x:Int, y:Int) -> String{
return "\(x) with \(y)"
}
let bar = foo(1, 2) // gives "1 with 2"
Я хочу выполнить эту функцию, чтобы "исправить" значение для x
, поэтому сделайте следующее:
func fooCurry(x:Int) -> (Int -> String) {
func curry(y:Int) -> String {
return foo(x, y)
}
return curry
}
Вышеприведенная функция возвращает новую функцию, которая может быть использована следующим образом:
let curriedFoo = fooCurry(1)
let barWithCurry = curriedFoo(2) // gives "1 with 2"
Функция, возвращаемая fooCurry
, имеет подпись (Int -> String)
, что означает, что параметр не имеет внешнего имени.
Ответ 4
Не лучший синтаксис, но если вы хотите обойти его сейчас, вы можете использовать следующие функции для основных карри:
func foo(x:Int) -> Int -> String {
return {
return "\(x) with \($0)"
}
}
Тогда вы можете просто сделать:
let bar = foo(1)
bar(2) //-> 1 with 2
Теперь очевидно, что проблема с этим становится очевидной, если вы хотите написать функцию curried для трубопровода четыре Int
, например:
func makerAdders(a:Int)(b:Int)(c:Int)(d:Int) {...}
будет выглядеть следующим образом:
func add(a:Int) -> Int -> Int -> Int -> Int {
return {
b in return {
c in return {
d in return a + b + c + d
}
}
}
}
Внутренние замыкания делают его немного лучше, чем использование внутренних функций, но снова он побеждает цель симпатичного синтаксиса func add(a:Int)(b:Int)(c:Int)(d:Int) {return a+b+c+d}
.
Ответ 5
Определенно ошибка в компиляторе, насколько я могу судить. До тех пор, пока он не будет исправлен, вы можете получить правильную карриную версию любой функции, используя эти функции (обратите внимание, что я включил случаи для двух и трех аргументов, расширяя ваш досуг:
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) } } }
}
Просто используйте:
curry(addTwoNumbers)(1)(2)