Perl, Haskell, stuff
"Currying" is a simple idea that is surprisingly powerful on the one hand, and which was surprisingly hard (at least for me) to get my head around - possibly because the concept didn't exist natively in the languages I learnt first.
When you declare a function in currying style, each argument is taken one at a time, returning a new, more specialised function each time, until the function is finally executed at the end.
Consider this function:
(Note we're assuming that Perl has argument lists... which it can do
with Devel::Declare, but we'll come to that in a bit). If this was
currying style then we wouldn't call it with
sub add ($left, $right) {
return $left + $right;
}
but instead
my $answer = add (1, 3); # 4
my $answer = add(1) # a function with $left bound to 1
->(3) # now executed with $right bound to 3
sub add {
my $left = shift;
return sub {
my $right = shift;
return $left + $right;
};
}
That isn't very pretty or convenient though... handily there are several
modules to encapsulate this behaviour on CPAN. One of them is my
Sub::Curried. The docs mention some of the other modules with
similar functionality: mine, which uses the shiny goodness of
Devel::Declare, has the advantage that you can declare a
curried subroutine with a simple, perlish syntax: in fact you do it more
or less exactly like the example I gave above. (The difference is that
we can't override the sub keyword, so we create a new one,
'curry':
curry add ($left, $right) {
return $left + $right;
}
Using D::D, the moment the Perl parser sees a symbol 'curry' being
compiled, it hands control to our custom parser, which then injects code
into the source while it's still being compiled. We can do some cunning
stuff, including telling it "Hey, when you get to the end of the scope
you're compiling, inject some more text!"
I used to keep hold of an array @filled of the partially
applied arguments and then apply all in one go at the end. But it seems
to be more elegant to actually transform into sometihng like the
"vanilla" example I gave above. I say "something like" but it's
actually little more complicated:
Yikes! The extra boilerplate is there to make sure that we get some
niceties:
sub add {
return ROUTINE unless @_; # a reference to this subroutine
check_args(2, @_); # check we weren't called with >2 args
my $f = sub {
my $left = shift;
return ROUTINE ...
check_args... # check we weren't called with >1 arg
my $f = sub {
my $right = shift;
return $left + $right; # actually do the thing
};
$f = ...
};
# now call the subroutine for each
$f = $f->(shift) for @_;
return $f;
}
package My::Class;
use base 'Class::Accessor';
__PACKAGE__->add_accessor('foo');
__PACKAGE__->add_accessor('bar');
__PACKAGE__->add_accessor('baz');
__PACKAGE__ refers to the current package, so this is the same as
writing:
My::Class->add_accessor('foo');
...
It's also utterly hideous. Moose on the other hand provides a syntax
like this:
package My::Class;
use Moose;
has 'foo' => ...
has 'bar' => ...
has 'baz' => ...
What's going on? Incredibly, 'has' is actually a class method just like
'add_accessor' was! But the leftmost argument (the invocant, usually
referred to as $self for object methods, or $class for
class methods) has been curried into it. This is because Perl's
importing is dynamic and instead of just copying the method.
*{CALLER::has} = \&has;
It can do somethingl like this:
*{CALLER::has} = has($CALLER); # assuming a currying 'has'
add = (+) -- alias
add 1 2 -- result is 3
(+) 1 2 -- also 3
You can also take 'sections' of these operators, by 'partially applying'
either the left or the right hand side.
add2 = (+ 2)
halve = (/ 2)
reciprocal = (1.0 /)
This isn't the same as currying, though you could implement sections
with curried functions:
curry divide ($left, $right) {
$left / $right
}
my $reciprocal = divide(1); # 1 / $ARG
my $halve = flip(divide)->(2); # $ARG / 2
That's rather ugly though, and remembering to flip the
arguments is annoying. So, again with Devel::Declare I
implemented
Sub::Section
(not yet on CPAN, the github repo is linked for now).
my $add2 = op(+ 2);
my $halve = op(/ 2);
my $contains_foo = op(=~ 'foo');
And of course:
my $greet = op("Hello " .);
say $greet->('World');
Osfameron's blog on Haskell, Perl programming, stuff.
Dave Rolsky
May 4th, 2009 at 8:24 am
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766
Programmer
May 4th, 2009 at 2:03 pm
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766
dude
May 4th, 2009 at 7:58 pm
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766
A hardcore Perl programmer
May 4th, 2009 at 10:41 pm
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766
osfameron
May 4th, 2009 at 11:06 pm
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766
Antti-Juhani Kaijanaho
May 5th, 2009 at 12:21 am
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766
Programmer
May 5th, 2009 at 3:23 pm
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766
Programmer
May 5th, 2009 at 3:25 pm
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766
Is currying monadic? - Just another lambdabananacamel,
May 7th, 2009 at 2:24 pm
Warning: preg_replace_callback() [function.preg-replace-callback]: Unknown modifier '|' in /var/www/blog/wp-content/plugins/text-control/text-control/markdown.php on line 766