drbean has asked for the wisdom of the Perl Monks concerning the following question:

On page 259 of HOP, MJD is talking of a linked list whose nodes are only constructed when the subroutine, tail is evaluated. The code for tail is similar to the following:
sub tail { my $list = shift; if ( ref( $list->[1] eq 'CODE' ) { return $s->[1]->() ); else { return $s->[1] } }
The code to construct the list, a list of the numbers from m to n, is:
sub upto { my ($m, $n) = @_; return if $m > $n; node( $m, promise { upto($m+1, $n) } ); }
where
sub promise (&) { $_[0] }
and:
sub node { my ($head, $tail) = @_; return [$head, $tail]; }
According to MJD, the tail() function sees the promise and invokes the anonymous promise function, which in turn invokes upto($m+1, $n). When I try this code out on Fedora 9 with perl-5.10.0, I get the error:
'Can't call method "promise" on an undefined value.'
It is apparently parsing the block argument to promise as an indirect method call on the non-existent object { upto($m+1, $n) } If I wrap the block argument to promise in parentheses, I get the errors:
Odd number of elements in anonymous hash at stream.pl line 19. Use of uninitialized value in anonymous hash ({}) at stream.pl line 19 +.
If I then disambiguate the thing in braces as a block with { return upto($m+1, $n) }, undef is returned. And if I replace the braces in the original line with parentheses, like
node( $m, promise ( upto($m+1, $n) ) );
the function is eagerly evaluated, not lazily. So, what do I tell MJD? I think this probably worked before. Is this a problem with newer perls?

Replies are listed 'Best First'.
Re: lazy evaluation of sub arg
by Anonymous Monk on Dec 17, 2008 at 11:42 UTC
      My problem appears to be the result of where 'sub promise (&) { $_[0] }' is placed in the file. If it is placed after the definition of the upto subroutine which uses it, I get the error message as before. If it is placed BEFORE the definition of the upto subroutine, it works as the book says.

      I didn't think the placement of subroutines mattered in a file. Perhaps the subroutine prototype on the definition of promise is turning it into an anonymous sub.

        Perhaps the subroutine prototype on the definition of promise is turning it into an anonymous sub.

        Prototypes change the parsing of code, and they can only change the parsing of subsequent code. When you declare that a subroutine takes a block argument with a prototype, the lexer has to know that that block represents an anonymous subroutine, not a hash reference.

Re: lazy evaluation of sub arg
by AnomalousMonk (Archbishop) on Dec 17, 2008 at 14:15 UTC
    I don't have time at the moment to check this out thoroughly, but I suspect the problem may lie with the order of declaration/definition and invocation of a prototyped function.

    A prototyped function such as promise() is properly invoked only after the function is either declared or defined. In the code shown in your post, I see promise() invoked before the function is defined, and there is no prototype declaration for the function shown at all. This may just be an artifact of composing the post (an entirely self-contained executable example is always preferable), but it is something to consider.

    Update: I posted this before I saw drbean's first reply. I think he or she is on the right track now.