On Sat, Apr 05, 2003 at 03:22:17PM -0700, Tom Christiansen wrote:
: >When you write:
: 
: >    (1..Inf) equal (0..Inf)
: 
: >I'd like Perl to consider that false rather than having a blank look
: >on its face for a long time.  
: 
: The price of that consideration would be to give the Mathematicians
: blank looks on *their* faces for a very long time instead.  Certainly,
: they'll be quick to tell you there are just as many whole numbers
: as naturals.  So they won't know what you mean by equal up there.

Eh?  Why should a mathematician jump to the conclusion that I'm
comparing sizes of the ordered lists rather than comparing the
individual elements?

: The Engineers might also be perplexed if you make that false, but
: for rather different reasons.  I think that you will have to define
: your "equal" operator in a way contrary to their respective
: expectations, because both have ways of thinking that could quite
: reasonably lead them to expect the answer to the expression above
: to come out to be false, not true.

Er, it *is* false, not true.  I guess that makes me an Engineer.  :-)

: Practically speaking, I'm not sure how--even whether--you *could*
: define it.  One is tempted to attempt something like saying that
: operator "equal" is true of a *lazy*, *infinite* list if and only
: if elements 0..N of both lists were each themselves "equal", and
: then only blessedly finite values of N.
: 
: But where then do you stop?  If N is 1, then (1..Inf) and (1..Inf:2)
: are ok.  If N is 2, meaning to check both the first pair from each
: list and also the second one, they aren't.  However, if N is true,
: (1..Inf) and (1, 2..Inf:2) are certainly ok.
: 
: In fact, that definition seems trivial to break.  Given a known N
: steps of comparison, the lazy lists (1..Inf) and (1..N-1, (N..Inf:2))
: would both test equal in the first N positions and differ in position
: N+1.  Therefore, we can always break any operator that tests the
: first N positions of both lazy lists, and thus that definition would
: be wrong.

You're assuming that the computer isn't smart about where the list
of numbers goes from enumerated to rule-generated, and that rule
generators can't be compared.  And they can't, in general, but
the .. operator is not general, but specific, and does know how
to compare the abstractions.

: The reason Mr Engineer might expect false would be if they thought you were
: eventually testing against Inf.  Due to his experience in numerical
: programming, he sees NaN and Inf having certain behaviors that no pure
: mathematician would even countenance.  On a system whose system nummifier
: knows things like Inf and NaN already, you see this happening even today.
: Witness real Perl:
: 
:     % perl -e 'printf "%g\n", NaN'
:     nan
:     % perl -e 'printf "%g\n",  1 + NaN'
:     nan
:     % perl -e 'printf "%g\n", 42 * NaN'
:     nan
:     % perl -e 'printf "%g\n", Nan == NaN'
:     0
:     % perl -e 'printf "%g\n", 1+Nan == NaN'
:     0
:     % perl -le 'printf "%g\n", Inf'
:     inf
:     % perl -le 'printf "%g\n", 1+Inf'
:     inf
:     % perl -le 'printf "%g\n", 2+Inf'
:     inf
:     % perl -e 'printf "%g\n", Inf == Inf'
:     1
:     % perl -e 'printf "%g\n", Inf == -Inf'
:     0
:     % perl -e 'printf "%g\n", 1+Inf == Inf'
:     1
:     % perl -e 'printf "%g\n", Inf + Inf' 
:     inf
:     % perl -e 'printf "%g\n", Inf * Inf'
:     inf
:     % perl -e 'printf "%g\n", Inf / Inf'
:     nan

Yes, but now you're talking about Inf in the context of numeric
operators rather than the .. range constructor, which knows better than
to ever try to evaluate Inf.  To the .. operator, "Inf" doesn't mean
"infinity".  It means "and so on...".  In fact, as the design currently
stands you can also write those as:

    (1...) equal (0...)

There, no more infinities.  :-)

: In other words, if you treat Inf as any particular number (which Mr
: Mathematician stridently yet somewhat ineffectually reminds you that are
: *not* allowed to do!), then you may get peculiar results.  Heck, you could
: probably then get Mr Engineer to agree that the lazy lists (1..Inf) and
: (0..Inf) are the same in the *last* N positions for all values of N, and
: since you could just select N to be equal (ahem) to the length (ahem**Inf)
: of your list, they must be equal. :-)

Again, you seem to be thinking that C<equal> would take the size of
both sides as if they were arrays.  I think of (1..Inf) more as a funny
kind of arbitrarily extensible string, and C<equal> as a comparison
"character" by "character", only they happen to be list elements instead.

One could *almost* extend C<eq> to have this semantics when applied to
lists.  But it breaks down when you recursively want to do polymorphic
== vs eq.  Whereas C<< $a equal $b >> would perhaps have a few smarts
about comparing dissimilar types, though not as much as ~~ does.

: Mr Mathematician, purist that he is, has of course long ago thrown up his
: hands in disgust, contempt, or both, and stormed out of the room.  To him,
: most of those Perl examples given above were utter nonsense: how can you
: say 1+Inf?  It bothers him to talk about Inf+1, and 1..Inf will be
: problematic, too, since to say 1..Inf is also to say there must exist some
: number whose successor is Inf.  And of course, there isn't.  Which is why
: Inf is not a valid operand for numerical questions in Mr Mathematician's
: platonically purist world of ideas.  But practical Mr Engineer has defined
: his own Inf in which you can do limited otherwise apparently numerical
: operations, because it was *practical* for him to do so.  He had work to
: do, and needed some new rules.

Sounds good to me, but then I'm an Engineer.  I like practical...

: While Mr Mathematician won't put up with comparing numbers and infinities,
: he's quite comfortable with comparing *infinities* themselves.  He's
: comfortable with infinite sets, and he's comfortable with infinite series,
: too, which is what these lists seem to be.  I'm not sure that his
: experience with infinite series will help us much here, because you see, 
: those aren't finite (duh).  It's all fine to talk about the limit 
: of some convergent infinite series like the sum of 1 / (2 ** N) as 
: N goes from 1 to Inf, but that doesn't really seem applicable to us here.

I think if Mr Mathematician wants to compare those kinds of infinities he's
more than welcome to define his own classes with their own C<equal> operator.
Unless, of course, the PDL have already beat him to it...

: So instead of thinking about infinite series, perhaps Mr Mathematician will
: when seeing your expressions (0..Inf) and (1..Inf) think of infinite 
: sets.  Certainly (0..Inf) corresponds to the Whole Numbers and (1..Inf)
: corresponds to the Natural Numbers, so this isn't a great stretch.

Sets aren't ordered, while ranges are.

: Perilously, the notion of comparing infinite sets takes you down Cantor
: Lane, an infinitely long road whose alleys threaten madness.  There, there
: exists a notion of "equal" that is defined to be true whenever elements of
: both infinite-set operands can be paired up sequentially--if you can make a
: one-to-one correspondence between enumerable set members.  Under that
: definition, these all hold true
: 
:     (0..Inf)              equal   (1..Inf) 
: 
:     (1..Inf)              equal   (1..Inf:2) 
: 
:     (1..Inf:2)                    equal   (1..Inf:5) 
: 
:     (1..Inf)              equal   (1..Inf:100) 
: 
:     (1..Inf)              equal   (1..Inf:Googleplex) 
: 
:     (The Set of Integers)   equal   (The Set of Rationals)
: 
: And therefore, Mr Mathematician would not be surprised by a definition of
: equals that allowed all of those to come out saying that they are true.
: 
: However, Mr Mathematician would therefore also expect any sort of testing of 
: 
:     (The Set of Integers)   equal   (The Set of Reals) 
: 
: to come out not true but false, due to Mr Cantor's Diagonalization Proof.
: Eek.  Let's please not go there.

Eek.  Wasn't planning to.

: Thankfully, we don't even have real numbers on a computer, just
: finite-sized sets of rationals masquerading as real numbers.  Only on a
: computer are there "more" rationals than integers, and well, even there it
: seems to me that given equal bitlength of N in both int and float types,
: that, well, perlifically speaking, (1..2**N) equal (1..2**N), eh? :-)
: 
: Anyway, all fun and games with Messrs Engineer and Mathematician,
: you still want to find some sensible way of comparing lazily evaluated
: infinite lists so that you could get some sort of answer.  But what
: is that answer?  Or what is *an* answer?  Can there even *be* one?

The Halting Problem is only a problem in the general case, and some
subset of the specific cases.  Fortunately, computers never get
discouraged by generalities.

: >So whatever equivalence and ordering operators we end up with, they
: >had better be able to do lazy comparisons of characters or elements
: >and give up as soon as they know the answer.  In fact, they need to
: >be smarter than that if we also want:
: 
: >    (0..Inf) equal (0..Inf)
: 
: >to run in finite time.  Lazy arrays need to delegate the operation
: >to their underlying generators whenever possible.
: 
: As I've outlined above, I'm not completely certain that that strategy--or
: in fact *any* possibly strategy--is necessarily guaranteed to provide a
: sensible answer to what may or may not be a sensible question after all.

Hmm, all I want is a polymorphic C<equal> operator that can compare
apples to apples and oranges to oranges, with the occasional
apple-to-orange comparison thrown in via multimethods to make sure
things like C<< 1 equal "1" >> are true.  The particular case of
comparing two abstract list generators seems (in the specific case
of ranges, anyway) to be amenably to some amount of analysis, at
least to the point of recognizing when the generators are no longer
amenable to analysis.  The only real "math" that has to be done by
(0...) equal (1...)  is comparing 0 to 1, once you've determined that
they're both infinite lists.  Similarly, (1..Inf:1) equal (1..Inf:2)
would have to compare the steps, but that's about it.

Finite ranges are slightly hairier insofar as you have to determine whether
the range is big enough that differing steps are effective:

    (1..1:2) equal (1..1:3)     # true
    (1..7:2) equal (1..7:3)     # false

But that can still be evaluated without "triggering" the generators.

On the other hand, generators like:

    <$handle1> equal <$handle2>

are just gonna have to chug through the two streams to compare all
the lines.  Darn...  :-)

(Well, actually, if both streams are known to represent files,
we could probably optimize it somewhat.  But suppose one of them
of them is a socket...)

Hmm.  If C<equal> wants a list on either side, perhaps it has a
very low precedence near "or".  But maybe it's more straightforward
to keep it the same as "eq" and friends, and require parens around
lists.  That seems cleaner, and clearer.  Forcing parens around
a list is not always evil.

Larry

Reply via email to