How would I do the equivalent of Prototype's Enumerator.detect in Perl with the least amount of code?

functional-programming, perl

Solution

You say you don't want a module, but this is exactly what the `first` function in List::Util does. That's a core module, so it should be available everywhere.

use List::Util qw(first);
my $first = first { some condition } @array;

If you insist on not using a module, you could copy the implementation out of List::Util. If somebody knew a faster way to do it, it would be in there. (Note that List::Util includes an XS implementation, so that's probably faster than any pure-Perl approach. It also has a pure-Perl version of `first`, in List::Util::PP.)

Note that the value being tested is passed to the subroutine in `$_` and not as a parameter. This is a convenience when you're using the `first { some condition} @values` form, but is something you have to remember if you're using a regular subroutine. Some more examples:

use 5.010; # I want to use 'say'; nothing else here is 5.10 specific
use List::Util qw(first);

say first { $_ > 3 } 1 .. 10;  # prints 4

sub wanted { $_ > 4 }; # note we're using $_ not $_[0]
say first \&wanted, 1 .. 10;   # prints 5

my $want = \&wanted;         # Get a subroutine reference
say first \&$want, 1 .. 10;  # This is how you pass a reference in a scalar

# someFunc expects a parameter instead of looking at $_
say first { someFunc($_) } 1 .. 10; 

Problem

Lately I've been thinking a lot about functional programming. Perl offers quite a few tools to go that way, however there's something I haven't been able to find yet. Prototype has the function detect for enumerators, the descriptions is simply this: ``` Enumerator.detect(iterator[, context]) -> firstElement | undefined Finds the first element for which the iterator returns true. ``` Enumerator in this case is any list while iterator is a reference to a function, which is applied in turn on each element of the list. I am looking for something like this to apply in situations where performance is important, i.e. when stopping upon encountering a match saves time by disregarding the rest of the list. I am also looking for a solution that would not involve loading any extra module, so if possible it should be done with builtins only. And if possible, it should be as concise as this for example: ``` my @result = map function @array; ```

Original source