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
Actually, Moose could implement has() without the curring. It could just use caller() to figure out the package to which the attribute should be added.
I think the currying version is a little more elegant, though.
Programmer
May 4th, 2009 at 2:03 pm
1) "Sections are currying". Putting an operator in parens makes that operator become prefix, so: (+) 1 2 is the same as 1 + 2. (+) 1 would be a partially applied function, i.e. curried.
2) What is the point of posting Perl stuff to planet Haskell? Are you trying to advertise Perl to Haskell people? Haskell people tend to want a strongly typed language and they probably want to work with something cutting edge. Not dynamically typed and obsolete.
dude
May 4th, 2009 at 7:58 pm
Lol, previous poster seems to have accidentally listed his name as 'Programmer'
A hardcore Perl programmer
May 4th, 2009 at 10:41 pm
Obsolete you say ... I say no .
"The wise man knows he doesn’t know. The fool doesn’t know he doesn’t know." -(Lao Tzu)
osfameron
May 4th, 2009 at 11:06 pm
Programmer:
1) Sections aren't exactly currying are they? Consider (1-) versus (-1). There's the implicit 'flip' depending on whether it's the Left or Right hand which is partially applied.
2) Many people in the Haskell community have been positive even about the FP-related Perl stuff I've posted, as many of the concepts and implementation details are of interest (even if these are baby steps compared to the headier delights to be found on Planet Haskell). I'll have a word with the Planet people about restricting the feed to my posts tagged "FP" (but that would still have included this post, for example).
Antti-Juhani Kaijanaho
May 5th, 2009 at 12:21 am
Planet Haskell is not about Haskell, it is about Haskell people and what they do, think and write. Many of us do in fact – gasp – program in other languages as well, and so we also occasionally post about other languages.
There are no off topic posts. There is only the question whether the blog belongs in Planet at all. Answering that question does lead us sometimes to only feeding a part of a blog to Planet), but I prefer to avoid that, since it tends to lead to too restrictive feeds (given that we want more than just the Haskell geeking).
(Speaking with my Planet Haskell admin hat on, but NOT for the whole Planet Haskell team.)
Programmer
May 5th, 2009 at 3:23 pm
Programming in other languages is good, and expected. Programming in horribly designed languages that have no advantages over more modern languages is neither good nor expected.
Programmer
May 5th, 2009 at 3:25 pm
And Osfameron, it's syntactic sugar and I must admit I didn't know (1 - ) would work. In either case it does end up working because of currying, but there is obviously more to it.
Is currying monadic? - Just another lambdabananacamel,
May 7th, 2009 at 2:24 pm
[...] a question that came up while I've been trying to implement currying in Perl: is Currying monadic? I've tried a couple of times, but not managed to explain what I mean very [...]