$x+$y
es una función de dos argumentos ($x, $y)
,
pero puede verse también como una función de un argumento $x
. ¿Cómo?.
La clave esta en pensar en la función suma como una función
que cuando recibe el primer argumento
$x
devuelve como resultado una función sub { $x+$_[0] }
la cual suma a su argumento el primer argumento $x
.
Para saber mas sobre currying
consulte el libro
Higher Order Perl
[13].
El término currying hace alusión al lógico americano
Haskell Curry (1900-1982) que
popularizó el concepto en 1930. Al parecer Gottlob Frege ya
había introducido la idea en 1893. Moses Schönfinkel la
redescubrió en 1924.
El siguiente ejemplo muestra una función curry
que recibe como argumento una función
y retorna una función que currifica esa función:
Cuando a la función se le pasa un argumento adicional se obtiene una nueva función:
Sigue un ejemplo de uso:
15 die "Error\n" unless @ARGV; 16 my $cprod = curry(sub { $_[0]*$_[1] }); 17 my $doble = $cprod->(2); 18 my @dobles = map { $doble->($_) } @ARGV; 19 print "@dobles\n"; 20 21 my $cfirst = curry(\&first); 22 my $fodd = $cfirst->( sub { $_ % 2 } ); # Primer impar 23 print $fodd->(@ARGV)."\n"; lhp@nereida:~/Lperl/src$ currying2.pl 4 8 12 9 23 25 8 16 24 18 46 50 9
Veamos el código y una ejecución:
lhp@nereida:~/Lperl/src$ cat -n currying2.pl 1 #!/usr/bin/perl -w 2 use strict; 3 use List::Util qw(first); 4 5 sub curry { 6 my $f = shift; # Referencia a una función de dos o mas argumentos 7 8 return sub { # Retorna función como f pero con un arg. menos 9 my $x = shift; 10 my $fx = sub { $f->($x, @_) }; 11 return $fx; 12 }; 13 }
La técnica de currificación transforma una función ordinaria en una fábrica de funciones (function factory). Al llamar a la fábrica con un parámetro nos devuelve una nueva función.
curry(\&List::Util::sum)->(4)->(1..5)
?
Si tiene dudas lea
la siguiente sesión con el depurador:
lhp@nereida:~/Lperl/src$ perl -wd currying2.pl main::(currying2.pl:15): die "Error\n" unless @ARGV; DB<1> $f = \&List::Util::sum DB<2> $g = curry($f) DB<3> $h = $g->(4) DB<4> x $h->(1..5) 0 19
Veamos otro ejemplo de currificación. La función map
es una función de dos argumentos: el primero es código
y el segundo una lista. La función retorna una lista.
Matemáticamente:
donde denota las funciones de en y denota las listas de objetos de tipo .
Si la currificamos la convertiremos en una función de un sólo argumento que retorna funciones:
Así pues - para una función dada - es una función que actúa sobre una lista y retorna una lista. Podríamos usarla como sigue:
lhp@nereida:~/Lperl/src/hop/Chap7$ sed -ne '11,$p' cmap2.pl | cat -n 1 my $sizes = cmap { -s $_ }; 2 my $rand20 = cmap { int(rand(20)) }; 3 local $a = 0; 4 my $pref = cmap { $_ += $a; $a = $_ }; 5 6 my @s = $sizes->(@ARGV); 7 my @r = $rand20->(1..5); 8 my @p = $pref->(1..5); 9 10 print "Tamaños = @s\n"; 11 print "Aleatorio = @r\n"; 12 print "Suma de prefijos = @p\n";que al ejecutra resulta en:
lhp@nereida:~/Lperl/src/hop/Chap7$ cmap2.pl *.pm Tamaños = 650 1933 591 1713 Aleatorio = 18 11 1 8 12 Suma de prefijos = 1 3 6 10 15Veamos una implementación:
lhp@nereida:~/Lperl/src/hop/Chap7$ sed -ne '1,9p' cmap2.pl | cat -n 1 #!/usr/bin/perl -w 2 use strict; 3 4 sub cmap (&) { 5 my $f = shift; 6 return sub { 7 map { $f->($_) } @_ 8 }; 9 }