Tom Hughes wrote:
> > For example, in Perl you have for a long time been able to do this:
> >
> >    ($one, $two) = grep /$pat/, @data;
> >
> > However, what currently happens is grep goes to completion, then
> > discards possibly huge amounts of data just to return the first two
> > matches. For example, if @data was 20,000 elements long, you could
> > potentially save a good chunk of time if you only had to return the
> > first and/or second match, rather than finding 1000 only to throw 998
> > away.
>
> This could fall out of using iterators in the core but without
> grep itself having to know anything about the left hand side.
>
<...>
>
> The only problem with this scheme (and indeed I suspect with
> yours) is if the match expression has a side effect. This is
> even more of a problem when trying to apply the same optimisation
> to map because of the widespread use of map in a void context
> to apply a side effect to the elements.

RFC 123 'Builtin: lazy' describes a syntax for explicitly stating that your
operation does not have a side effect, and requests that a 'lazy
list'/iterator be used. It mentions grep as an example:

<quote>
What if adding laziness to a list context was up to the programmer
and passed through functions that can support it:

        for (lazy(grep {$h{$_}->STATE eq 'NY'} keys %h)){
                $h{$_}->send_advertisement();
        };


would cause a lazy list is passed to C<for>, and increment of
the object's "letters_sent_total" field might break the iteration.


        for (grep {$h{$_}->STATE eq 'NY'} lazy(keys %h)){
                $h{$_}->send_advertisement();
        };


causes a lazy list to be passed to our filter function C<grep>, saving
us from allocating the entire C<keys> array.  C<Grep> is still in
the default busy context, so it returns a busy array, which C<for>
can iterate over safely.
</quote>


Reply via email to