subroutines advanced

How to create higher-order functions in Perl?

Question

How to create higher-order functions in Perl?

How to Create Higher-Order Functions in Perl

In Perl, higher-order functions are subroutines that can take other subroutines as arguments, return subroutines as results, or both. This capability enables a functional programming style where you build flexible and reusable abstractions by manipulating code references.

Since Perl treats subroutines as first-class values with the sub keyword and code references, creating higher-order functions (HOFs) is quite natural. Perl’s flexibility, often described by the acronym TMTOWTDI ("There’s More Than One Way To Do It"), means you have multiple ways to pass, store, and return code references.

Key Concepts

  • Code references: Created with sub { ... } or \\&subname, these are scalar references to anonymous or named subroutines.
  • Passing subs as arguments: You can pass code refs to other subs and invoke them with the ->() syntax.
  • Returning subs from subs: A subroutine can return a code reference, which can later be called, allowing creation of closures.
  • Closures: Code references that capture variables from the enclosing scope, enabling stateful behavior.

Example: Creating a Higher-Order Function

Below is a simple example that demonstrates a higher-order function called make_multiplier. It takes a number and returns a subroutine reference that multiplies its argument by that number. This leverages Perl closures and code references:


#!/usr/bin/perl
use strict;
use warnings;

# Higher-order function: returns a sub ref that multiplies input by $factor
sub make_multiplier {
    my ($factor) = @_;
    return sub {
        my ($input) = @_;
        return $input * $factor;
    };
}

# Create a doubler and a tripler
my $doubler = make_multiplier(2);
my $tripler = make_multiplier(3);

print "5 doubled is ", $doubler->(5), "\n";  # prints 10
print "7 tripled is ", $tripler->(7), "\n";  # prints 21

# Another example: applying a function passed as argument
sub apply_function {
    my ($func, $value) = @_;
    return $func->($value);
}

my $square = sub { my $x = shift; return $x * $x };
print "Square of 6 is ", apply_function($square, 6), "\n";  # prints 36

Explanation

  • make_multiplier accepts a number, $factor, and returns an anonymous subroutine capturing this value via closure.
  • This returned subroutine can then be called on a value to multiply it by $factor.
  • The example also shows apply_function, a higher-order subroutine that takes a code reference and a value and calls the code reference on the value.
  • Use of ->() to invoke code references is required.
  • Strict and warnings pragmas are used to catch common mistakes.

Common Pitfalls

  • Forgetting to use ->() to call a code reference; writing $func($arg) will call a subroutine named $func, not a code reference.
  • Not properly capturing lexical variables in closures, leading to unexpected behavior if the variables change later.
  • Passing named subs by reference requires \\&subname syntax to get a code reference.
  • Beware of contexts: scalar vs list context can affect results when subs return lists.

Version Notes

This style of higher-order programming works in Perl 5 and later. Since Perl 5.10+, features like state variables can further enhance closure usage. No external modules are required.

In summary, building higher-order functions in Perl primarily involves carefully handling code references and closures. This enables powerful and reusable abstractions common in functional programming paradigms.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 7ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
5 doubled is 10
7 tripled is 21
Square of 6 is 36
STDERR
(empty)

Was this helpful?

Related Questions