On Wed, Dec 13, 2006 at 11:31:33AM -0800, Ovid wrote:
: In trying to compress a list, I wrote the following code:
: 
:   my $compress = do {
:       my $previous;
:       $compress = -> $x {
:           if !defined $previous or $x ne $previous {
:               $previous = $x;
:               $x;
:           }
:           else {
:               ();
:           }
:       };
:   }
:   my @compressed = map $compress, <a a a a b c c a a d e e e e>;
:   @compressed.say;
: 
: That's a bit more verbose than I intended, but that's partially because
: of this:
: 
:   my $compress = do {
:       my $previous;
:       $compress = -> $x {
:           if !defined $previous or $x ne $previous {
:               $previous = $x;
:               return $x;
:           }
:           else {
:               return ();
:           }
:       };
:   };
: 
: As soon as I put the return statements in an anonymous subroutine, I
: get this error message:
: 
:   *** Cannot use this control structure outside a 'routine' structure
:       at 99.pugs line 103, column 13-22
: 
: Take out the returns, and it works fine.  Can someone tell me what I'm
: missing?  Is this a bug.

Nope, spec.  S06 says:

    [Pointy block] also behaves like a block with respect to control
    exceptions.  If you C<return> from within a pointy block, it will
    return from the innermost enclosing C<sub> or C<method>, not the
    block itself.  It is referenced by C<&?BLOCK>, not C<&?ROUTINE>.

See also the section in S04 discussing control exceptions, where it says:

    A C<return> always exits from the lexically surrounding sub
    or method definition (that is, from a function officially declared
    with the C<sub>, C<method>, or C<submethod> keywords).  Pointy blocks
    and bare closures are transparent to C<return>.

So all you really need to do is change the pointy to an official sub:

    my $compress = do {
        my $previous;
        $compress = sub ($x) {
            if !defined $previous or $x ne $previous {
                $previous = $x;
                return $x;
            }
            else {
                return ();
            }
        }
    }

: Also, I noticed I accidentally left off the final semi-colon on the do
: block.  It ran anyway and that surprised me.

S04:

    Outside of any kind of expression brackets, a final closing curly
    on a line (not counting whitespace or comments) always reverts
    to the precedence of semicolon whether or not you put a semicolon
    after it.

Larry

Reply via email to