Tener una función f que toma argumentos x 1 , x 2 , ..., x n
- es decir. f: X 1 × X 2 ×… × X n → Y
- curry redefine f como una función tomando un solo argumento a 1 que se asigna a otra función más. Esta técnica es útil para aplicaciones parciales, por ejemplo, con una pow
función currificada que podríamos escribir exp = pow(e)
.
Ejemplo
Suponiendo que tenemos la siguiente función f tomando tres argumentos ( f: X 1 × X 2 × X 3 → Y ):
def f(a,b,c):
return a + b * c
Curry esta función nos deja con f_curry: X 1 → (X 2 → (X 3 → Y)) , si ahora llamamos a esa función dos veces con f_curry(1)(2)
, obtendríamos una función ( h
) equivalente a la siguiente devuelta:
def h(c):
return 1 + 2 * c
La función curry f
podría escribirse así (Python 3):
def f_curry(a):
def g_curry(b):
def h(c):
return a + b * c
return h
return g_curry
Desafío
Su desafío será curry una función como se describe anteriormente, aquí están las reglas:
- La entrada será una función de caja negra que toma al menos 2 argumentos
- La función de entrada siempre tendrá un número fijo de argumentos (a diferencia
printf
o similar, nota: debe admitir funciones con cualquier número de argumentos ≥2) - Si su lenguaje usa funciones curriculares por defecto (por ejemplo, Haskell), puede esperar que la función de entrada se defina sobre N -tuplas, en lugar de una "función de orden superior"
- Puede tomar el número de argumentos como entrada
- La salida será el equivalente al curry de la entrada *
- Puede suponer que la función de salida solo será:
- llamado con menos o igual al número de argumentos que toma la función de entrada
- llamado con argumentos del tipo correcto
* Esto significaría para una entrada f
con N
argumentos y una salida h
que para todos los argumentos válidos a1,…,aN
contiene eso f(a1,a2,…,aN) == h(a1)(a2)…(aN)
.
def f(a,b,c): return a + b * c
y la salida esdef f_curry(a): def g_curry(b): def h(c): return a + b * c return h return g_curry
?f
(que se define en alguna parte) y la salida debería ser algo equivalente af_curry
. O la entrada seríalambda a,b,c: a+b*c
y la salida una función equivalente af_curry
.Respuestas:
JavaScript (ES6), 35 bytes
fuente
Idris , 204 bytes
Pruébalo en línea!
¡Suena como un trabajo para personas dependientes! Bien quizás.
C es una función de tipo curry. Dado un vector de tipos a = [t 1 , t 2 ,… t n ] y una función de tipo T: HVect a → Type , devuelve un nuevo tipo:
Aquí, HVect es el tipo de vector heterogéneo del Preludio Idris, el tipo de n -tuplas cuyos elementos son de n tipos diferentes.
c es una función que toma una y T como argumentos implícitos, y luego convierte una uncurried función
f
de tipo ((b: HVect a) → T b) en un curry uno de tipo C a T .( C simplemente describe lo que deseamos hacer; c en realidad lo hace. Pero no podemos escapar sin definir C , ya que Idris exige que cada definición de nivel superior tenga una firma de tipo).
El enlace TIO ofrece un ejemplo de uso. Si definimos una función en 3-tuplas (Nat, Nat, String) de la siguiente manera:
entonces
uncurried [3, 4, "th"]
produce el mismo resultado quec uncurried 3 4 "th"
. Idris infiere los argumentosa=[Nat, Nat, String]
yT=const String
para nosotros, creo.Basé este código en esta esencia de timjb.
fuente
HVect
por defecto,HVect
es esencialmente una tupla que puedes deshacer.Python 3 ,
5453 bytesPruébalo en línea!
fuente
R , 96 bytes
Pruébalo en línea!
Versión anterior (97 bytes)
-1 byte gracias a @JayCE
fuente
Coco , 54 bytes
Pruébalo en línea!
Coco , 40 bytes
Puerto de la respuesta de Python de Erik .
Pruébalo en línea!
fuente
Python 2 , 60 bytes
Pruébalo en línea!
El pie de página es un probador que usa STDIN de la siguiente manera por línea:
[a,b,...]
)Tenga en cuenta que, mientras que una lista de los argumentos se proporciona como entrada en el probador, en realidad, el equivalente curricular se antepone a la lista y la lista se reduce por la llamada a la función.
Ovs ha proporcionado amablemente una versión similar de 55 bytes :
Pruébalo en línea!
fuente
Coliflor , 84 bytes
Pruébalo en línea!
fuente
Perl 6 ,
4240 bytesPruébalo en línea!
-2 bytes gracias a Brad Gilbert b2gills .
fuente
*
, solo es necesario si hay algo después.assuming(*,1)
.Python 2 , 78 bytes
Pruébalo en línea!
fuente
Adjunto , 5 bytes
Pruébalo en línea!
Simple incorporado, en gran parte poco interesante. Pero, aquí hay una versión desde cero:
Adjunto, 35 bytes
Explicación:
fuente
Java 8, 46 + 318 = 364 bytes
Esta es una lambda al curry (hah) que toma una función y un recuento de argumentos y devuelve la función al curry.
Pruébalo en línea
Tipo de envío
Función de entrada
La entrada de función es un objeto con un único método (excluyendo métodos heredados) que representa la función. Tenga en cuenta que una interfaz funcional estándar no se puede utilizar como tipo de entrada porque se deben admitir funciones de (por ejemplo) 3 parámetros. También tenga en cuenta que
java.util.function.Function
se puede pasar una expresión lambda convertida a un tipo de tipo estándar (el método único esapply
).Se pueden declarar excepciones marcadas en la función de entrada, pero no se pueden lanzar (es decir, no se propagarán al llamador de la función de salida). Se presume que esto es aceptable porque las interfaces funcionales de Java no permiten excepciones comprobadas (y su propagación evitaría que el envío devuelva a
Function
). Excepciones de tiempo de ejecución (asignablesRuntimeException
oError
) se propagan.Función de salida
El resultado de la presentación es a
java.util.function.Function<Object, Object>
. Pensé en devolver un planoObject
con unapply
método (como en la entrada), pero luego se requeriría una reflexión para invocar el resultado, lo que parecía lo suficientemente inconveniente como para que no se pueda permitir, en particular, llamar todo el tiempo ya no sería posible en un solo expresión.Uso
Debido a que el envío devuelve una función de
Object
aObject
, la salida se puede invocar directamente (conapply
), pero los valores de retorno intermedios posteriores se deben convertir a un tipo apropiado (por ejemplojava.util.function.Function<Object, Object>
) antes de invocarlo. Consulte el TIO para algunos ejemplos de uso.Tenga en cuenta que en Java las funciones (es decir, los métodos) no son objetos de primera clase. Por lo tanto, la sintaxis utilizada en la viñeta de salida de la descripción del desafío no tiene sentido en Java. En lugar de
f(a1, a2, a3)
lo que tenemosf.apply(a1, a2, a3)
, y más def(a1)(a2)(a3)
lo que tenemosf.apply(a1).apply(a2).apply(a3)
.Limitaciones
Cuando se aplica un resultado intermedio (se agrega un argumento), el resultado es en realidad una copia mutada del resultado original. Por ejemplo, en este fragmento:
la línea 4 se imprimirá
4
, pero la línea 5 fallará, porque para ese momentoc2
ya tiene argumentos2
y2
(tenga en cuenta también esoc2 == c
). Esto viola el espíritu de curry, pero cumple con el requisito específico establecido en el desafío.Sin golf
Vea el TIO para obtener una copia sin golf.
fuente
Julia 0.6 , 48 bytes
Pruébalo en línea!
Puerto de la respuesta de Python de @ EricTheOutgolfer.
fuente
APL (Dyalog Classic) ,
5857 bytesPruébalo en línea!
Llamando a la sintaxis (con función de curry
g
, los argumentosx1
a través dex3
, y el número de argumentosn
):((n x1 f g) x2) x3
Requiere
⎕IO←1
fuente