Much earlier in this chapter, we mentioned that Perl has two main contexts, scalar context (for dealing with singular things) and list context (for dealing with plural things). Many of the traditional operators we've described so far have been strictly scalar in their operation. They always take singular arguments (or pairs of singular arguments for binary operators), and always produce a singular result, even in a list context. So if you write this:
@array = (1 + 2, 3 - 4, 5 * 6, 7 / 8);
you know that the list on the right side contains exactly four values, because the ordinary math operators always produce scalar values, even in the list context provided by the assignment to an array.
However, other Perl operators can produce either a scalar or a list value, depending on their context. They just "know" whether a scalar or a list is expected of them. But how will you know that? It turns out to be pretty easy to figure out, once you get your mind around a few key concepts.
First, list context has to be provided by something in the "surroundings". In the example above, the list assignment provides it. If you look at the various syntax summaries scattered throughout
Chapter 2
and
Chapter 3
, you'll see various operators that are defined to take a
LIST
as an argument. Those are the operators that
provide
a list context. Throughout this book,
LIST
is used as a specific technical term to mean "a syntactic construct that provides a list context". For example, if you look up
sort
, you'll find the syntax summary:
sort LIST
That means that sort provides a list context to its arguments.
Second, at compile time, any operator that takes a
LIST
provides a list context to each syntactic element of that
LIST
. So every top-level operator or entity in the
LIST
knows that it's supposed to produce the best list it knows how to produce. This means that if you say:
sort @guys, @gals, other();
then each of
@guys
,
@gals
, and
other()
knows that it's supposed to produce a list value.
Finally, at run-time, each of those
LIST
elements produces its list in turn, and then (this is important) all the separate lists are joined together, end to end, into a single list. And that squashed-flat, one-dimensional list is what is finally handed off to the function that wanted a
LIST
in the first place. So if
@guys
contains
(Fred,Barney)
,
@gals
contains
(Wilma,Betty)
, and the
other()
function returns the single-element list
(Dino)
, then the
LIST
that sort sees is
(Fred,Barney,Wilma,Betty,Dino)
and the
LIST
that
sort
returns is
(Barney,Betty,Dino,Fred,Wilma)
Some operators produce lists (like keys ), some consume them (like print ), and some transform lists into other lists (like sort ). Operators in the last category can be considered filters; only, unlike in the shell, the flow of data is from right to left, since list operators operate on their arguments passed in from the right. You can stack up several list operators in a row:
print reverse sort map {lc} keys %hash;
That takes the keys of
%hash
and returns them to the
map
function, which lowercases all the keys by applying the
lc
operator to each of them, and passes them to the
sort
function, which sorts them, and passes them to the
reverse
function, which reverses the order of the list elements, and passes them to the
print
function, which prints them.
As you can see, that's much easier to describe in Perl than in English.