http://qs321.pair.com?node_id=992996


in reply to The Scalar Range Operator

Can you use the scalar range operator with map and grep? Sure, but you have to be careful.

This does what you'd expect:

grep $_ == 3 .. $_ == 7, 1..10 # ==> (3, 4, 5, 6, 7)
because grep's first argument is evaluated as a scalar.

This is very puzzling:

map $_ == 3 .. $_ == 7, 1..10 # ==> (0, 0, 0, 0, 0, 0, 1, 0, 0, 0)
until you remember that map's first argument is evaluated as a list. What you meant, of course, was:
map scalar($_ == 3 .. $_ == 7), 1..10 # ==> (,,1,2,3,4,5E0,,,)
-- the expected result.

The puzzling case above gets even more puzzling if we show the list that map returns for each input:

map $_ == 3 .. $_ == 7, 1 # ==> (0) map $_ == 3 .. $_ == 7, 2 # ==> (0) map $_ == 3 .. $_ == 7, 3 # ==> () map $_ == 3 .. $_ == 7, 4 # ==> (0) map $_ == 3 .. $_ == 7, 5 # ==> (0) map $_ == 3 .. $_ == 7, 6 # ==> (0) map $_ == 3 .. $_ == 7, 7 # ==> (0, 1) map $_ == 3 .. $_ == 7, 8 # ==> (0) map $_ == 3 .. $_ == 7, 9 # ==> (0) map $_ == 3 .. $_ == 7, 10 # ==> (0)
we get the same ten elements as before, though in an unexpected way. The first line is evaluating:
1 == 3 .. 1 == 7
which is
"" .. ""
Remember that this is being evaluated in list context (because we forgot the scalar()). So, our scalar range operator has accidentally become a list range operator. The final clue is that the list range operator only does string magic (e.g. ("a".."z")) if the strings are non-empty. Otherwise the arguments are converted to integers, in this case zeros:
0 .. 0
which is just a list containing a single zero, as we saw above.

The other cases are now easy to understand.

map $_ == 3 .. $_ == 7, 3
is (1 .. ""), which is converted to (1 .. 0), which gives an empty list. Similarly,
map $_ == 3 .. $_ == 7, 7
is ("" .. 1) which gives (0, 1).