Ken Fox wrote:
> Jeremy Howard wrote:
> > (..-1) == map -__ (1..);
>
> That really confuses me. If the sequence (-4..-1) is (-4, -3,
> -2, -1) then I don't see how your semantics are consistent. I'll
> admit (reverse map -__ (1..)) is the same as (..-1) but reverse
> on a stream is undefined. (It should be a run-time error.)
>
Yes, they're not identical. What I mean of course is:
(..-1) == reverse(map -__ (1..));
But my point is that the programmer shouldn't have to bother with this
detail. If you write (..-1) perl knows what you mean.
> Streams must have a head. Infinite sequences in general don't need
> a head, but streams IMHO aren't general infinite sequences.
>
I know MJD talked of streams and infinite lists as being interchangable
concepts, but the notion that
@list = ($head, promise())
is just one potential implementation. We _can_not_ actually use an infinite
(or semi-finite) list until we reduce it (through filtering [eg grep], or
mathematical combination [eg sum], or some combination). We can only reduce
an infinite list under one of the following restrictions:
1- We know the domain under which the predicate used in the filter is true,
or
2- We know a mathematical 'short-cut' such as 'sum of a geometric series =
a/(1-r)'
There is no general way of finding a 'short-cut' for reduce(f(__,__), @a),
so we can't expect perl to deal with (2) for us. Therefore (1) is the only
restriction we can use, and therefore:
* We can not use an infinite list until we define a finite domain of its
indexes.
We can define this domain through some kind of 'stopping criteria'. Possible
criteria types include:
- Define the range of the indexes to test
- Define the number of items to return
- Define the time to search for.
If you accept that we need to define a domain to reduce a list, then you can
see that we can usefully talk of reverse(map -__ (1..)), because reverse()
is evaluated lazily and can be applied once the finite domain is known.
Note that under my definition of what you can do to a list (you must reduce
it before you output it), the following is not valid perl:
print (1..); # Error, attempt to output infinite list
You could argue that, procedurally speaking, this has some meaning because
you can signal to perl when you want it to stop outputting. But this
argument comes from thinking of (1..) as a stream, which it's not, it's a
list.
> One thing that would make sequences composed with .. more useful
> would be to allow the right hand side to be a function of one
> argument. Then the set of all negative numbers is (-1..__-1) which
> is the same as map -__ (1..). The set of all integer powers of two
> is (1..__*2). (But map __*2 (1..) is the set of all positive even
> numbers.) Another cool sequence is (1..__*-1+1) which alternates
> (1, 0, 1, 0, 1, ...). (Damian probably already thought of this
> though. I should go read RFC 24.)
>
I certainly think it would be nice to say:
(1..:3)
where ':3' defines a step size. But then I guess you're saying this
generalises to:
(i0..:f(__)) == i0, f(i0), f(f(i0), ...
(Note that I'm keeping the ':' notation, because then it's clear that we're
talking about a generation rule, not an upper bound). Now I write it like
this, wouldn't it be nice if we could also say:
(1..:f(__)) == apply(f(__), (1..); # But I digress!
Yes, that would be pretty cool.