From: Hal Niner
Subject: (= 0/0 0/0)
Date: 
Message-ID: <1533d93d.0312111057.c8222f@posting.google.com>
Hi,

shouldn't 

> (= 0/0 0/0) => NIL

or 

> (= 0/0 0/0) => T

instead of giving out division by zero?  0/0 is different from 1/0,
which is the non-existent number n such that 1 x n = 0.

The actual result of that expression depends of what you think 0/0 is.

I personally feel that 0/0 is any number n such that 0 x n = 0, that
is all numbers.

From: Kent M Pitman
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <sfwhe07f9iw.fsf@shell01.TheWorld.com>
····@cyberspace.org (Hal Niner) writes:

> Hi,
> 
> shouldn't 
> 
> > (= 0/0 0/0) => NIL
> 
> or 
> 
> > (= 0/0 0/0) => T
> 
> instead of giving out division by zero?  0/0 is different from 1/0,
> which is the non-existent number n such that 1 x n = 0.
> 
> The actual result of that expression depends of what you think 0/0 is.
> 
> I personally feel that 0/0 is any number n such that 0 x n = 0, that
> is all numbers.

This is probably the difference between mathematics and engineering.

When I see 0/0, what I see is "this is a program bug".  The place "any
number" comes into my thinking is the sense in which I think "any number
I put here would have been just as bad".

In practice, the most likely place you'll see 0/0 is 

 (/ (reduce #'+ y) (length y))

where y is null.  And I can tell you, I don't want Lisp returning any
old number and having my table of average incomes say

 Residents   Average Yearly Income
 ---------   ------------------
     0         $ -9,347,425.36
       
just because -9347425.36 x 0 = 0.

It's an error because the programmer needs to know it's an error.
Mathemeticians can do their own handling, but me in this case, I want
"---" to come back, and I don't see any way that / all by itself is
going to know to do that.

Or if what you want is the literal rational 0/0 to do something different
than the function call (/ 0 0), then I don't like that for several reasons,
at least one of which is "it's irregular" and makes it hard to express the
rules for rational simplification.
From: Hal Niner
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <1533d93d.0312120547.7661df44@posting.google.com>
> 
>  (/ (reduce #'+ y) (length y))
> 
> where y is null.  And I can tell you, I don't want Lisp returning any
> old number and having my table of average incomes say
> 

I understand this, but shouldn't it be the case where taking a length
of a null list gives you some sort of error/warning/exception?

Oh, wait, no 

(eq '() nil) => T

OK, then. ;)
From: Kent M Pitman
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <sfw3cbqnkpy.fsf@shell01.TheWorld.com>
····@cyberspace.org (Hal Niner) writes:

> > 
> >  (/ (reduce #'+ y) (length y))
> > 
> > where y is null.  And I can tell you, I don't want Lisp returning any
> > old number and having my table of average incomes say
> > 
> 
> I understand this, but shouldn't it be the case where taking a length
> of a null list gives you some sort of error/warning/exception?

did you mean to write "the false value" here instead of "a null list"?

> Oh, wait, no 
> 
> (eq '() nil) => T

stylistically, you are here comparing the empty list to the false value.
why that would be relevant to the question of whether you could take length
of the empty list, I don't know.   of course, if you'd been wondering why
you can take length of the false value, this remark would make perfect sense.

> OK, then. ;)

In spite of the smiley, I had the impression there was some unresolved issue
here, so i figured i'd explore it.

-----

Legitimately taking length of a null list is quite common, especially in
cases like:

 (case (length x)
   ((0) ...)
   ((1) ...)
   (otherwise ...))

(although I usually use a bounded-length operator for this these days,
so it doesn't waste time computing the number 347 as the length, only
to compare it to 0 and 1).

And in principle, you could do base cases of iteration as

 (defun find-it (x list)
   (cond ((= (length list) 0) nil)
         (t (find-it x (cdr x)))))

[if we didn't mind find-it being O(n^2)].  It's for speed, in effect, that
we prefer (NULL x) to (= (LENGTH x) 0).   Though there are some aesthetic
benefits [like program termination] to having NULL available for writing
LENGTH itself.
From: Pascal Bourguignon
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <87k752ots6.fsf@thalassa.informatimago.com>
Kent M Pitman <······@nhplace.com> writes:

> ····@cyberspace.org (Hal Niner) writes:
> 
> > > 
> > >  (/ (reduce #'+ y) (length y))
> > > 
> > > where y is null.  And I can tell you, I don't want Lisp returning any
> > > old number and having my table of average incomes say
> > > 
> > 
> > I understand this, but shouldn't it be the case where taking a length
> > of a null list gives you some sort of error/warning/exception?
> 
> did you mean to write "the false value" here instead of "a null list"?
> 
> > Oh, wait, no 
> > 
> > (eq '() nil) => T
> 
> stylistically, you are here comparing the empty list to the false value.
> why that would be relevant to the question of whether you could take length
> of the empty list, I don't know.   of course, if you'd been wondering why
> you can take length of the false value, this remark would make perfect sense.
> 
> > OK, then. ;)
> 
> In spite of the smiley, I had the impression there was some unresolved issue
> here, so i figured i'd explore it.

I  think he  was refering  to the  fact that  there is  no distinction
between "null" lists and empty lists, ie. (eq (eq '() nil) t).


I don't know what  a "null" list would be. There could  be no list, an
empty list, or  some other, non empty, lists. In  Common Lisp, this is
expressed with indicators:

(defun what-kind-of-list-p (&optional (the-list nil given-p))
    (cond
      ((not given-p)   :no-list)
      ((null the-list) :empty-list)
      (t               :other-list)))

[39]> (what-kind-of-list-p)
:NO-LIST
[40]> (what-kind-of-list-p ())
:EMPTY-LIST
[41]> (what-kind-of-list-p '(a))
:OTHER-LIST


Or the  "no-list" case  could be represented  with a  special :no-list
 token (in scheme we could use #f).

(defun what-kind-of-list-p (the-list)
    (cond
      ((eq :no-list the-list)   :no-list)
      ((null the-list)          :empty-list)
      (t                        :other-list)))

[46]> (what-kind-of-list-p :no-list)
:NO-LIST
[47]> (what-kind-of-list-p '())
:EMPTY-LIST
[48]> (what-kind-of-list-p '(a))
:OTHER-LIST



-- 
__Pascal_Bourguignon__                              .  *   * . * .* .
http://www.informatimago.com/                        .   *   .   .*
There is no worse tyranny than to force             * .  . /\  ()  . *
a man to pay for what he does not                    . .  / .\   . * .
want merely because you think it                    .*.  / *  \  . .
would be good for him. -- Robert Heinlein             . /*   o \     .
http://www.theadvocates.org/                        *   '''||'''   .
SCO Spam-magnet: ··········@sco.com                 ******************
From: Kalle Olavi Niemitalo
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <87u145all9.fsf@Astalo.kon.iki.fi>
Kent M Pitman <······@nhplace.com> writes:

> ····@cyberspace.org (Hal Niner) writes:
>
>> I understand this, but shouldn't it be the case where taking a length
>> of a null list gives you some sort of error/warning/exception?
>
> did you mean to write "the false value" here instead of "a null list"?

I suspect hal9 meant a null pointer as in C or Java, where it is
a special value that can be assigned in a variable of any pointer
type.

Common Lisp does not have such a construct.  It has the NIL
symbol, which is also the empty list and the false value; but it
is not automatically included in other types.  For example, if
you declare that a variable will always hold a STRING, then NIL
is not a valid value for it.  If you want to allow NIL too,
declare the type as (or string null), or just omit the
declaration altogether.
From: Kent M Pitman
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <sfw1xr8vi30.fsf@shell01.TheWorld.com>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> Kent M Pitman <······@nhplace.com> writes:
> 
> > ····@cyberspace.org (Hal Niner) writes:
> >
> >> I understand this, but shouldn't it be the case where taking a length
> >> of a null list gives you some sort of error/warning/exception?
> >
> > did you mean to write "the false value" here instead of "a null list"?
> 
> I suspect hal9 meant a null pointer as in C or Java, where it is
> a special value that can be assigned in a variable of any pointer
> type.
> 
> Common Lisp does not have such a construct.  It has the NIL
> symbol, which is also the empty list and the false value; but it
> is not automatically included in other types.  For example, if
> you declare that a variable will always hold a STRING, then NIL
> is not a valid value for it.  If you want to allow NIL too,
> declare the type as (or string null), or just omit the
> declaration altogether.

Ah, yes.  Probably.  

People should be wary of false cognates, both in real life and in 
computer languages.

The vaguely more equivalent notion in CL is 'unbound', which is not
something you can assign, but is something that global variables can
start with if they have not been assigned.  No lexical variable ever
starts unbound, although some I believe can start with values of
implementation-defined nature (e.g., if you let-bind a variable
declared to be of a type that cannot hold NIL).
From: Paul F. Dietz
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <prudnfztAc1dqEaiRVn-tA@dls.net>
Kent M Pitman wrote:

>   No lexical variable ever
> starts unbound, although some I believe can start with values of
> implementation-defined nature (e.g., if you let-bind a variable
> declared to be of a type that cannot hold NIL).

According to the definition of LET and LET*, if you omit the initform
the variable is initialized to NIL.  A program that declares the
variable to be some type that does not contain NIL would be nonconforming.

	Paul
From: Kent M Pitman
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <sfwbrqc3atc.fsf@shell01.TheWorld.com>
"Paul F. Dietz" <·····@dls.net> writes:

> Kent M Pitman wrote:
> 
> >   No lexical variable ever
> > starts unbound, although some I believe can start with values of
> > implementation-defined nature (e.g., if you let-bind a variable
> > declared to be of a type that cannot hold NIL).
> 
> According to the definition of LET and LET*, if you omit the initform
> the variable is initialized to NIL.  A program that declares the
> variable to be some type that does not contain NIL would be nonconforming.

I suppose I should grub around and see if I agree that this is the
only relevant case.  I know we hassled over it enough that I don't
recall the outcome.  That's why I said "I believe", to flag that I
was not sure.
From: Kaz Kylheku
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <cf333042.0312111523.3224e702@posting.google.com>
····@cyberspace.org (Hal Niner) wrote in message news:<··························@posting.google.com>...
> Hi,
> 
> shouldn't 
> 
> > (= 0/0 0/0) => NIL
> 
> or 
> 
> > (= 0/0 0/0) => T

No. You are using =, which is a function. A function has no access to
the argument forms, only to the results of their evaluation. The
argument list (0/0 0/0) is evaluated left to right before = is called.
During this evaluation, a division by zero occurs.

> instead of giving out division by zero?  0/0 is different from 1/0,
> which is the non-existent number n such that 1 x n = 0.

In Lisp, a number is an actual object, not the set of solutions to an
equation. When you divide two integers, the result must be a valid
rational number.

> The actual result of that expression depends of what you think 0/0 is.
> 
> I personally feel that 0/0 is any number n such that 0 x n = 0, that
> is all numbers.

In that case, you have to implement your own arithmetic. The built-in
arithmetic that you get with Common Lisp is already probably more
complicated and robust than that of any other industrial programming
language.

In Lisp you can use the object system to define your own operators
like = + and so on in your own package, which are generic over all the
existing number types (i.e. backwards compatible with the built-in
functions over the existing combinations) and which extend to your own
kinds of numbers.

(defpackage :wacky-arithmetic
  (:use :cl)
  (:shadow :/ :=)) ;; note smiley

(in-package :wacky-arithmetic)

(defclass wacky-number () ...)

;; fall back on standard CL = for two ordinary numbers
(defmethod = ((left numbe r) (right number))
  (cl:= left right)) 

;; handle comparison of WACKY-NUMBER with a RATIONAL
(defmethod = ((left wacky-number) (right rational))
   ...)

;; handle division of two rationals with zero denominator
;; to obtain special WACKY-NUMBER denoting that quantity

(defmethod / ((numerator rational) (denominator rational))
  (if (zerop denominator)
    (make-instance 'wacky-number ... wacky arguments ...)
    (cl:/ numerator denominator)))
From: Pascal Bourguignon
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <87u147qcpb.fsf@thalassa.informatimago.com>
····@cyberspace.org (Hal Niner) writes:

> Hi,
> 
> shouldn't 
> 
> > (= 0/0 0/0) => NIL
> 
> or 
> 
> > (= 0/0 0/0) => T
> 
> instead of giving out division by zero?  0/0 is different from 1/0,
> which is the non-existent number n such that 1 x n = 0.
> 
> The actual result of that expression depends of what you think 0/0 is.
> 
> I personally feel that 0/0 is any number n such that 0 x n = 0, that
> is all numbers.

It depends on how you arrived to the 0 denominators.

(defun f (x) (sin x))
(defun g (x) x)
(defun h (x) (/ x 2))

(= (f 0) 0.0)
(= (g 0) 0.0)
(= (h 0) 0.0)

but    (= (lim x -> 0 (/ (f x) (g x))) 1)
while  (= (lim x -> 0 (/ (f x) (h x))) 2)

So you have 0/0 = 1 on the one hand, and 0/0 = 2 on the other hand
and clearly, 0/0 /= 0/0

Where do your zeroes come from?

-- 
__Pascal_Bourguignon__                              .  *   * . * .* .
http://www.informatimago.com/                        .   *   .   .*
There is no worse tyranny than to force             * .  . /\  ()  . *
a man to pay for what he does not                    . .  / .\   . * .
want merely because you think it                    .*.  / *  \  . .
would be good for him. -- Robert Heinlein             . /*   o \     .
http://www.theadvocates.org/                        *   '''||'''   .
SCO Spam-magnet: ··········@sco.com                 ******************
From: Richard Fateman
Subject: Re: (= 0/0 0/0)
Date: 
Message-ID: <brb618$eo2$1@agate.berkeley.edu>
There is actually a way of defining 0/0 as well as 1/0
which makes CL rational arithmetic simpler rather than
more complicated.
0/0 is essentially like a floating point NaN, and
1/0 is like an (unsigned) infinity. Though there is
an argument to allow -1/0 also...


remember...
a/b +c/d =  (ad+cb)/bd   reduced to lowest terms?
if a/b  is 0/0  you get ... 0/0 ...
if a/b  is 1/0   you get  (d+0)/0 .  reduce to lowest terms, 1/0
unless d is also 0, in which case you get 0/0

a/b* (c/d) =  (ac)/bd

works similarly.

So it may be that you have more special case checks to
exclude 0/0 and 1/0 than if you allow them.

I wrote this up some time ago.

is 0/0 = 0/0  ?  Just like (= NaN NaN).

Cheers.
RJF

Pascal Bourguignon wrote:

> ····@cyberspace.org (Hal Niner) writes:
> 
> 
>>Hi,
>>
>>shouldn't 
>>
>>
>>>(= 0/0 0/0) => NIL
>>
>>or 
>>
>>
>>>(= 0/0 0/0) => T
>>
>>instead of giving out division by zero?  0/0 is different from 1/0,
>>which is the non-existent number n such that 1 x n = 0.
>>
>>The actual result of that expression depends of what you think 0/0 is.
>>
>>I personally feel that 0/0 is any number n such that 0 x n = 0, that
>>is all numbers.
> 
> 
> It depends on how you arrived to the 0 denominators.
> 
> (defun f (x) (sin x))
> (defun g (x) x)
> (defun h (x) (/ x 2))
> 
> (= (f 0) 0.0)
> (= (g 0) 0.0)
> (= (h 0) 0.0)
> 
> but    (= (lim x -> 0 (/ (f x) (g x))) 1)
> while  (= (lim x -> 0 (/ (f x) (h x))) 2)
> 
> So you have 0/0 = 1 on the one hand, and 0/0 = 2 on the other hand
> and clearly, 0/0 /= 0/0
> 
> Where do your zeroes come from?
>