2012-03-22 17 views
8

lectura a través del artículo de Wikipedia sobre las funciones de primera clase, hay una bonita mesa de soporte de idiomas para los diversos aspectos de la programación funcional: http://en.wikipedia.org/wiki/First-class_function#Language_support¿Admite JavaScript la aplicación de función parcial?

JavaScript está catalogado como no tener aplicación de función parcial. Sin embargo, existen técnicas para crear una función que devuelve una función que con algunos de los parámetros almacenados en un cierre, es decir:

var add = function(a, b){ 
    return a + b; 
}, 
apply = function(fn, a){ 
    return function(b){ 
     return fn(a, b); 
    } 
}, 
addFive = apply(add, 5); 

console.log(addFive(2)); // prints 7 

¿Es esta aplicación de función no parcial? De lo contrario, ¿podría alguien proporcionar un ejemplo de aplicación de función parcial en otro idioma y explicar cómo es diferente?

Gracias!

Respuesta

5

Lo que muestra es un ejemplo de funciones de orden superior, funciones que toman funciones como argumentos y/o funciones de retorno.

La aplicación parcial es algo diferente. Here a Haskell example:

add  :: Int -> Int -> Int 
add x y = x + y 

addOne = add 1 

add es una función que toma dos Int y devuelve un Int, denotado como Int -> Int -> Int. Si no está familiarizado con la sintaxis, en Javascript esta más o menos se vería así:

/** 
* @param int x 
* @param int y 
* @return int 
*/ 
function add(x, y) { 
    return x + y; 
} 

add 1 llama a esta función con un solo parámetro, que devuelve una nueva función que toma una Int y devuelve un Int (Int -> Int) . La función add no se diseñó explícitamente para ser una función de orden superior, simplemente se aplicó parcialmente.

+0

Perdóname, no estoy familiarizado con la sintaxis de Haskell. ¿La firma de la función para 'add' que dice" 'add' toma dos Ints y devuelve un Int"? ¿Esto quiere decir que invocar una función que toma 2 parámetros con solo 1 devuelve implícitamente la función parcialmente aplicada? –

+0

Traducido a Javascript. Sí, en términos simples, 'Int -> Int -> Int 'significa que toma dos' Int' y devuelve uno. Sin embargo, tal vez más correcto, transformará un 'Int' y otro' Int' en otro 'Int'. Real Haskellers todavía tendrá un problema con mi terminología, supongo, pero para el profano esto debería funcionar. : o) – deceze

+1

Supongo que sí - es decir, 'add' actuaría así: http://paste.pocoo.org/show/569340/ – ThiefMaster

6

El concepto que debe buscar para entender esto se llama currying (después de Haskell B. Curry). Existe un isomorfismo entre las funciones de los parámetros n + 1 y una función con un parámetro que devuelve una función con n parámetros. Si aplica esto recursivamente, puede escribir una función de cualquier número de parámetros como una función para funcionar con funciones.

Esta es la razón por funciones en lenguajes funcionales generalmente se escriben como X -> Y -> Z sentido, esta es una función que toma un X y devuelve una función que toma un Y devolver un Z. Esta firma también significa que solo puede proporcionar un X y la función devolverá una función.

En Javascript, una función de dos parámetros tendrá la firma X * Y -> Z lo que significa que es una función que toma un par de X * Y y devuelve un Z. Sin embargo, no puedes suministrar la mitad de un par.

Hay dos maneras de salir de esta:

  • Siempre Curry manualmente su función. Su función add podría ser escrito como:

    var curryadd = function(a){ 
        return function(b){ return a + b; } 
    }; 
    

Con esta ahora tiene una función que tiene la signatur real Int -> Int -> Int que se necesita para la aplicación de la función parcial.Sin embargo, también debe asegurarse de llamar a esta función como curryadd(5)(10), lo cual no es natural.

  • Ofrecen funciones de orden superior, que curry sus funciones. En su caso, la aplicación hace dos cosas, curry su función de agregar y vincula el parámetro. Este puede dividirse en dos partes:

    var curry = function(fn) { 
        return function(a){ return function(b){ return fn(a,b); } } 
    }; 
    

En realidad, esto implementar el isomorfismo entre funciones con pares como argumentos y funciones que devuelven funciones. También hay una forma de escribir uncurry que hace lo mismo al revés.

Como tiene que hacer todo esto manualmente y no hay soporte de idioma directo, se dice que javascript no tiene una aplicación de función parcial (lo que no significa que no pueda agregarlo al idioma).

+0

Creo que olvidó algunas declaraciones 'return' en sus funciones internas. – ThiefMaster

+0

@ThiefMaster: Sí, lo noté más tarde, pero no tenía conexión a Internet para cambiarlo. Supongo que a veces los olvidas, si estás acostumbrado a los lenguajes funcionales, que no los necesitan. – LiKao

1

Como se menciona en las otras respuestas, lo que usted describe es currying; es una forma de aplicación parcial, como lo identifica.

Sin embargo, si lo que quiere es sólo una aplicación parcial, puede utilizar underscore.js, lo que añade un montón utilidades de programación funcionales: http://documentcloud.github.com/underscore/

+0

Gracias por la respuesta adicional. Utilizo subrayado y bastante técnicas de programación funcional en mi programación de JavaScript. Solo estaba buscando una aclaración de lo que significaba "aplicación de función parcial" en el artículo de Wikipedia. Ahora veo que se trata de una cuestión de soporte del idioma nativo en lugar de tener que implementarlo a través de funciones de orden superior. –

3
var func1 = function(a, b) { 
    return a + b; 
} 

var func2 = func1.bind(undefined, 3); 

func2(1); // 4 
func2(2); // 5 
func2(3); // 6 

cheque docs at developer.mozilla.org

+1

Esta parece ser la respuesta más directa, dado que 'bind' ahora es nativo del idioma. –

Cuestiones relacionadas