2011-03-11 17 views
8

Estoy tratando de crear curry function que se puede aplicar a cualquier función y devolver otra, con 1 de los argumentos aplicados. Propiedades que quieren tener:javascript currying

  1. Si la función tiene la única función de curry un argumento debe devolver el valor: f (a); curry (f, x) = f (x);
  2. Si la función tiene muchos argumentos, currey debe recuperar la función curried: g (a1, a2, .., aN); curry (g, x) = g2 (a2, .., aN): g2 (a2, .. aN) = g (x, a2, ..., aN)
  3. La propiedad de longitud de la función al curry debería funcionar "como sea ​​necesario" g.length = N => Curry (g, x) .length = N-1

Hay algunas implementaciones de curry en Marco Prototype y discusión en one blog. Pero esta implementación no es buena porque no funciona bien en funciones con solo un argumento (1), y también el atributo "longitud" de la función de retorno es 0 (3).

Por primera propiedad no es una aplicación fácil:

function curry(f,x) { 
    if (f.length == 1) return f(x); 
    ... 
} 

Pero no sé cómo trabajar con tercera regla, es decir, la función se puede Constucted como función interna, ya que habrá un Medio Ambiente y el léxico anidada podrá usar f:

function curry(f,x) { 
    return function() { ... } 
} 

pero en este caso ya no podré establecer explícitamente los parámetros. Por otra función de la mano se puede construir con 'nueva función' declaración, SMTH así:

function curry(f,x) { 
    var args = []; 
    for (var i=1; i<f.length; i++) { 
     args.push('a'+i); 
    } 
    var sa = args.join(); 
    return new Function(sa,"return f(x,"+sa+")"); 
} 

Pero en esta situación F y X no unida porque la función anónima se creará en Global léxico Medio Ambiente.

Así que las preguntas:

  1. ¿Hay alguna manera cuentan parámetros para establecer explícitamente al crear la función con la palabra clave function?
  2. ¿hay alguna manera de establecer el entorno de la función creado con la instrucción 'nueva función'?
  3. ¿Hay alguna manera de resolver mi problema de otra manera?
+1

El hecho de que una función sea * declarada * con un solo argumento no significa que no * acepte * más. – Pointy

+1

El primer requisito me parece asimétrico. Currying una función de un argumento debería devolver una función sin argumentos en mi opinión ... – 6502

+0

Sé que si la función declarada con algunos argumentos puede aceptar más, pero de todos modos puede haber una situación en la que quiera verificar el atributo de longitud y la solución romperá esta lógica. No hubo respuesta para 1 y 2 preguntas, pero el problema principal está resuelto, así que marqué la pregunta como resuelta – qnikst

Respuesta

6

La forma en que la biblioteca Functional implementa que es tomar los parámetros pasados ​​a "de curry()" como para ser pasados ​​los primeros parámetros. El resultado de la función de la operación "curry" tomará los parámetros adicionales que se pasen cuando se invoque y los agregará al final de la lista de argumentos. No se preocupa en absoluto por la longitud de la lista de argumentos, porque eso no es algo fijo en JavaScript en general, así que realmente no tiene sentido.

Por lo tanto:

var curry = myFunction.curry("Tuesday", x + y); 

así que llamar:

curry(100, true); 

habrá como llamar a:

myFunction("Tuesday", x + y, 100, true); 

funcional tiene otra función llamada "parcial()" que permite una mayor sustitución controlada de parámetros. Cuando se llama "parcial()", se pasa en un argumento ficticio ("_") para indicar dónde "agujeros" están en la lista de argumentos:

var partialFunc = myFunction.partial("Tuesday", _, 100, true, _, "banana"); 

Esos dos "_" parámetros quiere decir que el resultado " partialFunc" debe caer dos primeros argumentos que se le pasan en esas ranuras en la lista de argumentos:

partialFunc(x + y, "Texas"); 

es, pues, como llamar a:

myFunction("Tuesday", x + y, 100, true, "Texas", "banana"); 

lo recomiendo conseguir que la biblioteca y mirar el código involucrado. Es sorprendentemente breve y claro.

Una cosa más: es importante tener en cuenta que, como JavaScript no es un lenguaje de evaluación diferida, esto no es realmente igual que la operación "curry" en un lenguaje funcional vago como Haskell. La diferencia es que los argumentos en "curry time" son evaluados y por lo tanto tipo de "cocinado" en el resultado. En un lenguaje perezoso, las cosas son diferentes.

3
function curry(fn, args) { 
    // no need to var these, they are scoped via argument list - we overwrite them 
    // convert the arguments to a real array: 
    args = [].slice.apply(arguments); 
    // first argument is a function: 
    fn = args.shift(); 
    return function() { 
    // get internal args 
    var iArgs = [].slice.apply(arguments); 
    // apply curried arguments, then our arguments: 
    return fn.apply(this, args.concat(iArgs)); 
    } 
} 

function add(a,b) { return a+b; } 
var add2 = curry(add, 2); 
alert(add2(5)); //7 

var hello = curry(add, "Hello "); 
alert(hello("World!")); 
2

Desde hace años he utilizado un prototipo de función para el curry que tiene este aspecto:

Function.prototype.curry = function curry() { 
    var fn = this, args = Array.prototype.slice.call(arguments); 
    return function curryed() { 
     return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))); 
    }; 
}; 

Tal vez se adapte a sus necesidades también.

Simplemente lo usa de esta manera:

function fn1(arg1,arg2) { /*...*/ } 

var fn1Curried = fn1.curry('whatever'); //sets arg1 

Se trabajará con cualquier número de argumentos.

0
function curry(func) { 
    var initial_args = [].slice.apply(arguments, [1]); 
    var func_args_length = func.length; 

    function curried(args) { 
     if (args.length >= func_args_length) { 
      return func.apply(null, args); 
     } 

     return function() { 
      return curried(args.concat([].slice.apply(arguments))); 
     }; 
    } 

    return curried(initial_args); 
} 
Cuestiones relacionadas