Currying in Perl

“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:

    sub add ($left, $right) {
        return $left + $right;
    }

(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

    my $answer = add (1, 3);  # 4

but instead

    my $answer = add(1) #  a function with $left bound to 1
                  ->(3) #  now executed with $right bound to 3

Implementation

This is actually quite simple to implement in pure vanilla Perl.

    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:

    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;
    }

Yikes! The extra boilerplate is there to make sure that we get some
niceties:

  • Die with informative error message if we’re called with too many
    arguments.

  • Handle being called with multiple arguments: i.e. treat add(1,2)
    the same as add(1)->(2)

  • When called with zero arguments, the sub returned is logically (and
    cutely!) an alias. (I think the ROUTINE trick isn’t needed, will
    probably disappear with a restructure)

  • Handle functions that return multiple values smoothly (not shown
    above)

Uses of currying

OK, so we’ve done a lot of furious work behind the scenes to make
something look very simple while doing a whole lot of extra work. But
why? When you program in Haskell, you’ll find currying useful at every
turn: it’s a hunch that it’d be useful in Perl too. There are certainly
some cute examples of it in common use:

Currying the invocant

Modules that do setup on a class would often use class methods: for
example:

    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'

Sections

In Haskell you can take references not just to functions, but to
operators.

    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');

Talk

I’ll be talking about Functional Perl at the
href="http://northwestengland.pm.org/meetings/004.html">NorthWestEngland
perlmongers tomorrow Tues 5th in Manchester, UK.

Comments

  1. Dave Rolsky says:

    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.

  2. Programmer says:

    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.

  3. dude says:

    Lol, previous poster seems to have accidentally listed his name as ‘Programmer’

  4. A hardcore Perl programmer says:

    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)

  5. osfameron says:

    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).

  6. 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.)

  7. Programmer says:

    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.

  8. Programmer says:

    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.

  1. [...] 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 [...]