[tpm] Dealing with nested map { grep {} }

Tom Legrady legrady at gmail.com
Tue Sep 26 10:53:25 PDT 2017


As an exercise, I'm implementing a RosettaCode challenge for a game 
between human and computer.

     const my $PLAYERS => qw( human computer );

I want to automatically access the appropriate opponent for each player, 
which allows core game logic of

     while ( $no_one_won ) {
         for my $player ( @PLAYERS ) {
             $self->player( $player )->take_turn( $OPPONENT{$player} );
         }
     }

But to initialize %OPPONENT, I would need to nest a grep{} inside a 
map{}, which leads to two instances of $_. Now perhaps the specification 
of the opponent should be part of the game object or of a player object, 
but I'm still curious how to resolve this problem in a single stage. Now 
obviously you can't compare $_ with $_ ...

     const my %OPPONENT => map { $_ => grep { $_ ne $_ } @PLAYERS } @PLAYERS

If it weren't a const object, we could do this in stages, though it's 
verbose and ugly:

     my %OPPONENT;
     for my $player ( @PLAYERS ) {
         $OPPONENT{$player} = grep { $_ ne $player } @PLAYERS
     }

But in the case of 'const my %OPPONENT', it's an error to attempt to 
vivify a key after the object has become restricted.

It worked fine if I replaced the inner grep{} with a subroutine call, 
not_me(), which would perform the grep away from the map{}. But then it 
occurred to me to perform a variable assignment within the map{}. Once 
we assign $a, we can safely redefined $_.

     const my %OPPONENT => map { my $a = $_; $a => grep { $_ ne $a} 
@PLAYERS } @PLAYERS

Tom


More information about the toronto-pm mailing list