RSS Feed

Curry

7

marzo 6, 2013 by - @pelicanorojo

Intro

Para contarles que es Curry me voy a basar en el libro 聽 “JavaScript Patterns – Stoyan Stefanov“. ( Lo pueden comprar en su librer铆a de confianza 馃槈 )

En este link tienen una def un poco m谩s gen茅rica, desatada del mundo JS.

“Curry es una t茅cnica de transformaci贸n de funciones que permite obtener a partir de una funci贸n A otra B que es la versi贸n parcialmente aplicada de A.” Despu茅s de la聽teor铆a聽vienen un par de formas de hacerlo con JavaScript.

Que es una aplicaci贸n y una aplicaci贸n parcial?

Podemos tomar con fines pr谩cticos hablando en un contexto menos matem谩tico y mas JS que una aplicaci贸n es como una llamada a funci贸n y que aplicar parcialmente una funci贸n es llamarla con no todos los argumentos esperados sino con algunos de los primeros. Como de esta forma no podemos obtener el resultado final que obtendr铆amos de pasarle todos los par谩metros, lo que se obtiene es una funci贸n que se puede llamar con los par谩metros restantes y devolver el resultado como si hubiese sido llamada con todos los par谩metros.

Implementaciones

Curry manual:

function sumar( x, y ) {
    if ( typeof y === 'undefined' ) { //detecci贸n de aplicaci贸n parcial
        return function ( y ) { //la transformaci贸n ( curring )
            return x + y;
        };
    } else {
        return x + y;//aplicaci贸n completa
    }
}

var sumaParcial = sumar( 4 );// Obtener suma parcialmente aplicada, memoriza x

var result = sumaParcial( 5 ); // uso de la versi贸n parcialmente aplicada, el 5 se usa para y que al sumarle la x memorizada ( 4 ) dar谩 como resultado 9. 

//Tambi茅n lo podemos usar as铆:
var result2 = sumar( 4 ) ( 5 );

En esta implementaci贸n del curry, la aplicaci贸n parcial est谩 en la misma funci贸n sumar, si vamos a usar mucho esta t茅cnica, se puede hacer una forma m谩s聽vers谩til聽que pueda aplicar curry a cualquier funci贸n que querramos en el libro aparece el ejemplo, la funci贸n schonfinkelize de 7 lineas que le pone curry a lo que se le cruce:

Curry pro

function schonfinkelize(fn) {
   var slice = Array.prototype.slice,
     stored_args = slice.call(arguments, 1);
   return function () {
      var new_args = slice.call(arguments),
         args = stored_args.concat(new_args);
      return fn.apply(null, args);
   };
}

//Ejemplo de uso:
// Funci贸n a modificar:
function echo( x ) {
  return x;
}

// Funci贸n modificada
var elephantFunction = schonfinkelize( echo, 'algo para recordar' );//La Transformaci贸n ( curring )

// Aplicaci贸n, en un objeto mock, o un objeto que necesita tener un m茅todo que devuelva siempre el mismo valor con fines de polimorfimo
var mock = {
   getMessage: elephantFunction
}

Mas info sobre apply en Patrones de Invocaci贸n de Funciones: this y en Modificando el contexto: call, apply y bind

Implementaci贸n de Underscore.js

Underscore viene con la funci贸n partial que permite hacer las partial applications, el ejemplo anterior, hecho con esta funcionalidad de underscore ser铆a :

var mock = {
   getMessage: _.partial( echo, 'algo para recordar' ) //La transformaci贸n ( curring )
}

Ejemplos de Uso:

Imag铆nense que tenemos una funci贸n densidad de tres variables de entrada ( x, y , z ) que nos devuelve la concentraci贸n de algo ( un compuesto por ejemplo ) en un cuerpo dado. Densidad podr铆a tener informaci贸n de una tomograf铆a computada o de un examen de resonancia magn茅tica nuclear, x podr铆a representar la dimensi贸n longitudinal de pies a cabeza, y con _.partial( densidad, 3 ), podr铆amos obtener un corte ( una聽imagen聽) de esa informaci贸n a 3聽cent铆metros聽de la planta de los pies.

Ok, que pasa si se nos fu茅 la mano con el fernet y queremos cortes que no sean perpendiculares a ninguno de los ejes xyz? Rta, tendr铆amos que aplicar un poco (bastante) de matem谩tica, como para obtener una funci贸n similar partial, pero que se llame por ejemplo slice que reciba como entrada un vector con un punto por donde debe pasar el corte y otro perpendicular al plano de corte, ejemplo: 聽corte = _.slice( [3, 0, 0], [0, 0, 1], densidad ) // el corte pasa por x = 3 y el vector normal es el que tiene solo componente z. 聽 La funci贸n devuelta tendr铆a dos variables de entrada, que ser铆an coordenadas x y y en el plano de corte ( que no necesariamente son las mismas que las originales).

Bueno, espero que les haya gustado.


  • matiasarriola

    Muy groso, esto me vol贸 la cabeza cuando aprend铆 algo de haskell :{D
    No conoc铆a el partial de underscore, viene al pelo.

  • tito hernandez

    Excelente entrada. De lo mejor que se ha publicado ultimamente en todos los blogs que leo 馃槈

  • pjnovas

    Copado post!, agrego un buen debate sobre este post en Twitter https://twitter.com/fernetjs/status/309285415536431104

  • http://twitter.com/AlejoNext Alejandro 脩ext

    Gracias por ese post!!

  • Pingback: quest protein bars

  • Pingback: Tony

  • Pingback: Nelson