swift - ¿Por qué las funciones al curry requieren nombres de parámetros externos?
currying (5)
Creo que es un error de compilación, su ejemplo debería funcionar como se describe en el libro The Swift Programming Language donde mencionan la declaración de funciones al curry:
func addTwoNumbers(a: Int)(b: Int) -> Int {
return a + b
}
addTwoNumbers(4)(5) // Returns 9
¡buen descubrimiento!
Dada esta simple función de curry:
func foo(x:Int)(y:Int)->String{
return "/(x) with /(y)"
}
Espero poder hacer algo como esto:
let bar = foo(1)
bar(2) //<- error: Missing argument label ''y:'' in call
Si rotulo la llamada a la bar
(como en la bar(y:2)
) todo funciona bien. Pero no entiendo por qué es necesario el nombre del parámetro. Hay alguna manera de evitarlo?
Lo obvio:
func foo(x:Int)(_ y:Int)->String ...
No parece funcionar.
Definitivamente un error en el compilador por lo que puedo decir. Hasta que se arregle, puede obtener una versión con currículum adecuado de cualquier función usando estas funciones (tenga en cuenta que he incluido casos para dos y tres argumentos, extendidos a su gusto:
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) } } }
}
Solo usa:
curry(addTwoNumbers)(1)(2)
Es un error, debe presentar un radar en bugreport.apple.com
Como confirmación, si coloca un guión bajo, como este
func foo(x: Int)(_ y: Int) -> String
recibes una advertencia
''_'' Extraño en el parámetro: ''y'' no tiene nombre de argumento de palabra clave
Entonces dice explícitamente que y
no tiene un nombre externo, pero aún así requiere uno cuando se le llama, lo que está claramente en contra de la especificación del idioma.
No es la mejor sintaxis, pero si quiere evitarlo por ahora, puede usar lo siguiente para las funciones básicas de curry:
func foo(x:Int) -> Int -> String {
return {
return "/(x) with /($0)"
}
}
Entonces simplemente puedes hacer:
let bar = foo(1)
bar(2) //-> 1 with 2
Ahora, obviamente, el problema con esto se vuelve obvio cuando se desea escribir una función al curry para canalizar cuatro Int
s, por ejemplo:
func makerAdders(a:Int)(b:Int)(c:Int)(d:Int) {...}
se vuelve así:
func add(a:Int) -> Int -> Int -> Int -> Int {
return {
b in return {
c in return {
d in return a + b + c + d
}
}
}
}
Los cierres internos lo hacen un poco mejor que usar las funciones internas, pero de nuevo anula el propósito de la func add(a:Int)(b:Int)(c:Int)(d:Int) {return a+b+c+d}
nice func add(a:Int)(b:Int)(c:Int)(d:Int) {return a+b+c+d}
sintaxis.
No estoy seguro de entender completamente tu curry. Aquí está mi opinión sobre él. Tengo una función foo como sigue:
func foo(x:Int, y:Int) -> String{
return "/(x) with /(y)"
}
let bar = foo(1, 2) // gives "1 with 2"
Deseo curry esta función para "arreglar" el valor de x
, así que haga lo siguiente:
func fooCurry(x:Int) -> (Int -> String) {
func curry(y:Int) -> String {
return foo(x, y)
}
return curry
}
Lo anterior devuelve una nueva función que se puede utilizar de la siguiente manera:
let curriedFoo = fooCurry(1)
let barWithCurry = curriedFoo(2) // gives "1 with 2"
La función devuelta por fooCurry
tiene la firma (Int -> String)
, lo que significa que el parámetro no tiene un nombre externo.