There has been some discussion recently about lazy-evaluated semi-infinite
lists. The biggest point of disagreement is over lists of the form (..n)
and (..), i.e., semi-infinite lists bounded from above and semi-infinite
lists which are unbounded.
I believe there are some reasonable semantics which can be had with such
lists, and that these semantics are reasonably perlish.
Several proposals have mentioned an extended form of the .. operator that
is capable of accepting increments, like so:
@a = (1..100:10) # @a = (1,11,21,...,91).
This notation makes it easier to work with ranges, and makes it easier to
show the sematics I see for semi-infinite lists.
Many people have stated that @positives=(1..) is acceptable, but
@negatives=(..-1) is not, because @positives has a beginning and @negatives
does not. As such, operations like map(), grep(), reduce(), etc, working
on @negatives are nonsensical.
Nonsense...
Perl provides methods of accessing each end of a list. For a normal list
@digits=(0..9), expressions like shift(@digits), unshift(@digits,@list),
and $digits[5] are all defined, and access @digits from the
right. Similarly, pop(@digits), push(@digits,@list), and $digits[-5] are
all defined and access @digits from the left. There is no reason why this
property can't be extended to semi-infinite lists either.
I think this table of results makes sense...
@a = (k..l:n) (k..:n) (..l:n) (..:n)
----------------------------------------------------------------
$a[i] (i>=0) k+i*n, if <l k+i*n ERROR ERROR
$a[-i] (i>0) $a[$#a-i+1] ERROR l-(i-1)*n ERROR
shift(@a) @a=(k+n..l:n) @a=(k+n..:n) ERROR ERROR
unshift(@a,0) @a=(0,k..l:n) @a=(0,k..:n) ERROR ERROR
pop(@a) @a=(k..l-n:n) ERROR @a=(..l-n:n) ERROR
push(@a,0) @a=(k..l:n,0) ERROR @a=(..l:n,0) ERROR
reverse(@a) see below @a=(..k:n) @a=(l..:n) ERROR
The issue with reverse (k..l:n) is that the last element is not l, but the
largest k+i*n <= l, so it's reversal can't be written as generally as the rest.
Please note: (..) still is not meaningful, because it can't be indexed.
map() and grep() are also meaningful:
@doubles = map { 2*$_ } (1..) # @doubles is (2,4,6,8,...)
@ndoubles = map { 2*$_ } (..-1) # @ndoubles is (...-8,-6,-4,-2)
@primes = grep {isprime($_)} (1..) # @primes is (2,3,5,7,11,...)
@nprimes = grep {isprime(-$_)} (..-1) # @nprimes is (..-5,-3,-2)
I am not sure if reduce makes sense in the context of semi-infinite lists
of either flavor.