Previous: Relational expressions, Up: Expressions [Contents][Index]
Ranges are a powerful way of describing an ordered list of tasks. Ranges come in three forms:
These are described with the following syntax:
<range>  ::=  ‘{’ <expr> [‘,’ <expr>]* [‘, ... ,’ <expr>] ‘}’ 
  ‘{’ <expr> [ FOR EACH
<ident>
IN
<range> [‘,’ <range>]* ]+ 

[ WHERE
<rel_expr>] ‘}’ 
Enumerated lists are the simplest type of range. They represent a list of explicitly specified values. For example, the range ‘{2**3, 2+4, 14/2, 83, 1+1+1, 0, 5*21}’ represents each of the seven numbers 8, 6, 7, 5, 3, 0, and 9 in turn. Duplicate values are allowed in enumerated lists so ‘{9, 3, 9, 5, 5, 5, 0, 1, 1, 3}’ represents ten numbers even though not all of them are unique.
Arithmetic and geometric progressions are specified by including the first few values of the progression, followed by an ellipsis, followed by the final value of the progression. A single initial value implies an arithmetic progression with increment of +/ 1, depending on whether the final value is greater or less than the initial value. Two initial values imply an arithmetic progression with an increment of secondfirst. If three or more initial values are provided, coNCePTuaL first looks for an arithmetic progression, then a geometric progression. If coNCePTuaL finds neither an arithmetic nor a geometric progression, it reevaluates all of the <expr>s in floatingpoint context (see Arithmetic expressions) and tries once again to find a geometric progression. If a pattern is still not found, a runtime error message is generated. As some examples of arithmetic and geometric range expressions, the range ‘{10, ..., 1E6}’ represents the values 10, 11, 12, 13, 14, 15, and so forth by ones up to 1,000,000; the range ‘{10, 12, ..., 1E6}’ represents the values 10, 12, 14, 16, and so forth by twos up to 1,000,000; and the range ‘{10, 100, 1000, ..., 1E6}’ represents the values 10, 100, 1000, 10000, 100000, and 1000000.
Arithmetic and geometric progressions do not necessarily include the final value. For example, the range ‘{1, 4, ..., 15}’ represents the values 1, 4, 7, 10, and 13 but not 15, even though 15 is specified as the final value of the range. Similarly, ‘{15, 12, ..., 1}’ represents the values 15, 12, 9, 6, and 3 but not 1, even though 1 is specified as the final value of the range. Progressions stop at or before the final value, never after. If the number following the ellipsis is less than (respectively, greater than) the first number in an increasing (respectively, decreasing) range (as in ‘{15, 25, ..., 5}’), then the range represents an empty list of values.
List comprehensions provide a way to combine and filter ranges to describe complex sequences of values with comparatively little code.^{14} A simple example is ‘{n FOR EACH n IN {1, ..., 10}}’, but this is not particularly useful, as the range ‘{1, ..., 10}’ represents the same list of values. However, replacing the expression ‘n’ with ‘n/2’ to get ‘{n/2 FOR EACH n IN {1, ..., 10}}’ returns the values 0, 1, 1, 2, 2, 3, 3, 4, 4, and 5, which would be more difficult to express without a list comprehension. We can even utilize only a subset of those values by applying a filter. For example, ‘{n/2 FOR EACH n IN {1, ..., 10} WHERE n/2 IS ODD}’ represents the values 1, 1, 3, 3, and 5. List comprehensions can be multivariate, as in the following example:
{diag+ofs FOR EACH diag IN {0, 11, ..., 99} FOR EACH ofs IN {1, 0, 1} WHERE diag+ofs IS IN {0, ..., 99}}
That single range expression represents all cells on the
tridiagonal of a 10x10 matrix, with cell 0
in the upper left and cell 99 in the
lower right. The first FOR EACH
generator binds
‘diag’ to each cell on the diagonal: 0, 11, 22, 33,
and so forth. The second FOR EACH
generator binds
‘ofs’ to each of 1, 0, and 1. The
‘WHERE’ predicate, which itself uses a range
expression, selects only those values of ‘diag’ and
‘ofs’ which which
0 <= diag+ofs <= 99.
The value ‘diag+ofs’ is returned for all values for
which the predicate is true. The following figure illustrates the
values described by the preceding range expression:
Here are a number of additional examples of range expressions and the values they represent:
⇒ 2, 2, 2, 2, 2, 2
⇒ 2
⇒ 2
⇒ 20, 30, 40, 50
⇒ 20, 30
⇒ 20
⇒ [empty]
⇒ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
⇒ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50
⇒ error→
⇒ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50
⇒ 2, 4, 8, 16, 32
⇒ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25
⇒ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25
⇒ 6561, 2187, 729, 243, 81, 27, 9, 3, 1
⇒ 100, 150, 225, 337, 506, 759, 1139, 1708, 2562, 3844, 5766, 8649
⇒ error→
⇒ 1, 1, 1, 4, 4, 4, 4, 4, 9, 9, 9, 9, 9, 9, 9, 16
⇒ 1, 3, 5, 10, 12, 14, 16, 21, 23, 25, 30, 32, 34, 36, 41, 43, 45, 50, 52, 54, 56, 61, 63, 65
The preceding examples used exclusively constant expressions. However, as indicated by the definition of <range> above, any arbitrary arithmetic expression (see Arithmetic expressions) is valid. Assuming that ‘x’ is currently bound to 123, the following expansion holds:
⇒ 1230, 1107, 984, 861, 738, 615, 492
Readers unfamilier with the concept of a list comprehension may want to consult the Wikipedia article on list comprehensions for more information.
Previous: Relational expressions, Up: Expressions [Contents][Index]