Skip to content
Closures and Currying
step 1/5

Reading — step 1 of 5

Learn

~1 min readClosures and Data

Perl closures capture lexical (my) variables by reference. The closure keeps the variable alive even after the enclosing scope exits.

use strict;
use warnings;

sub make_counter {
    my $count = 0;
    return sub {
        return ++$count;
    };
}

my $c1 = make_counter();
my $c2 = make_counter();
print $c1->(), "\n";   # 1
print $c1->(), "\n";   # 2
print $c2->(), "\n";   # 1 — separate $count
print $c1->(), "\n";   # 3

Each call to make_counter() creates a fresh $count. Each closure has its own.

Multiple closures sharing state — Perl's encapsulation pattern:

sub make_account {
    my ($balance) = @_;
    return {
        deposit  => sub { $balance += $_[0] },
        withdraw => sub { $balance -= $_[0] },
        balance  => sub { return $balance },
    };
}

my $a = make_account(100);
$a->{deposit}->(50);
$a->{withdraw}->(20);
print $a->{balance}->(), "\n";   # 130

The three closures share $balance. External code can't access it without going through them.

Currying — produce specialized functions:

sub adder {
    my ($x) = @_;
    return sub { $x + $_[0] };
}

my $add5 = adder(5);
my $add10 = adder(10);
print $add5->(7), "\n";    # 12
print $add10->(7), "\n";   # 17

@_ quirk: inside a closure, @_ is the closure's args, NOT the enclosing function's. Capture explicitly:

sub outer {
    my @outer_args = @_;     # capture
    return sub { print "outer had @outer_args, inner has @_\n" };
}

Closure-based dispatch tables — Perl-idiomatic:

my %ops = (
    add => sub { $_[0] + $_[1] },
    sub => sub { $_[0] - $_[1] },
    mul => sub { $_[0] * $_[1] },
);

my $result = $ops{add}->(3, 4);   # 7

Beats long if/elsif chains.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…

Closures and Currying — Perl Advanced