From: verec
Subject: my=
Date: 
Message-ID: <43c32f3a$0$87291$5a6aecb4@news.aaisp.net.uk>
Speaking of polyadic functions in another thread,
I investigated how I could write my own.

My goal was to have

(defun my= (...)

operate exactly like = does with respect
to both syntax and correctness.

I came up with:

1: (defun my= (&rest list)
2:   (flet ((bin= (&optional x y)
3:            (when (eq x y) x)))
4:     (when (reduce #'bin= list) t)))


1: used &rest to allow (my= 1 2 3) rather than (my= '(1 2 3))
2: used &optional because reduce calls bin= with either 0 or 2
   arguments
3: used "eq" rather than "=" because x may be nil
4: added a "when" otherwise the result is (nth n list)
   for some value of n, rather than T

CL-USER 41 > (my= 1 1 2)
NIL
CL-USER 42 > (my= 1 1 1)
T

Anything I missed? Another, more elegant way of doing this?
Did I just fell into the "easy to write inefficient Lisp code"
trap ?

Many thanks
--
JFB

From: Ron Garret
Subject: Re: my=
Date: 
Message-ID: <rNOSPAMon-97A1F5.23463109012006@news.gha.chartermi.net>
In article <·························@news.aaisp.net.uk>,
 verec <·····@mac.com> wrote:

> Speaking of polyadic functions in another thread,
> I investigated how I could write my own.
> 
> My goal was to have
> 
> (defun my= (...)
> 
> operate exactly like = does with respect
> to both syntax and correctness.
> 
> I came up with:
> 
> 1: (defun my= (&rest list)
> 2:   (flet ((bin= (&optional x y)
> 3:            (when (eq x y) x)))
> 4:     (when (reduce #'bin= list) t)))
> 
> 
> 1: used &rest to allow (my= 1 2 3) rather than (my= '(1 2 3))
> 2: used &optional because reduce calls bin= with either 0 or 2
>    arguments
> 3: used "eq" rather than "=" because x may be nil
> 4: added a "when" otherwise the result is (nth n list)
>    for some value of n, rather than T
> 
> CL-USER 41 > (my= 1 1 2)
> NIL
> CL-USER 42 > (my= 1 1 1)
> T
> 
> Anything I missed?

? (my= nil nil)
NIL
?
From: Pascal Bourguignon
Subject: Re: my=
Date: 
Message-ID: <87bqykaf96.fsf@thalassa.informatimago.com>
verec <·····@mac.com> writes:

> Speaking of polyadic functions in another thread,
> I investigated how I could write my own.
>
> My goal was to have
>
> (defun my= (...)
>
> operate exactly like = does with respect
> to both syntax and correctness.
>
> I came up with:
>
> 1: (defun my= (&rest list)
> 2:   (flet ((bin= (&optional x y)
> 3:            (when (eq x y) x)))
> 4:     (when (reduce #'bin= list) t)))
>
>
> 1: used &rest to allow (my= 1 2 3) rather than (my= '(1 2 3))
> 2: used &optional because reduce calls bin= with either 0 or 2
>    arguments
> 3: used "eq" rather than "=" because x may be nil
> 4: added a "when" otherwise the result is (nth n list)
>    for some value of n, rather than T
>
> CL-USER 41 > (my= 1 1 2)
> NIL
> CL-USER 42 > (my= 1 1 1)
> T
>
> Anything I missed? 

Yes, 


Big problem: (eq 1 1) -> NIL is legal.
             (eq 31280938091091 31280938091091) -> NIL is most probable.

Small problem: (= 'a 'a) --> error *** - =: A is not a number
               (my=  'a 'a) --> T


> Another, more elegant way of doing this?

(setf (symbol-function 'my=) (symbol-function 'cl:=))


> Did I just fell into the "easy to write inefficient Lisp code" trap ?

沒

If you're trying to re-implement Common Lisp, you should read CLHS.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"You can tell the Lisp programmers.  They have pockets full of punch
 cards with close parentheses on them." --> http://tinyurl.com/8ubpf
From: verec
Subject: Re: my=
Date: 
Message-ID: <43c33fd2$0$87291$5a6aecb4@news.aaisp.net.uk>
On 2006-01-10 04:17:09 +0000, Pascal Bourguignon <····@mouse-potato.com> said:

> verec <·····@mac.com> writes:
> 
>> Speaking of polyadic functions in another thread,
>> I investigated how I could write my own.
>> 
>> My goal was to have
>> 
>> (defun my= (...)
>> 
>> operate exactly like = does with respect
>> to both syntax and correctness.
>> 
>> I came up with:
>> 
>> 1: (defun my= (&rest list)
>> 2:   (flet ((bin= (&optional x y)
>> 3:            (when (eq x y) x)))
>> 4:     (when (reduce #'bin= list) t)))
>> 
>> 
>> 1: used &rest to allow (my= 1 2 3) rather than (my= '(1 2 3))
>> 2: used &optional because reduce calls bin= with either 0 or 2
>> arguments
>> 3: used "eq" rather than "=" because x may be nil
>> 4: added a "when" otherwise the result is (nth n list)
>> for some value of n, rather than T
>> 
>> CL-USER 41 > (my= 1 1 2)
>> NIL
>> CL-USER 42 > (my= 1 1 1)
>> T
> Big problem: (eq 1 1) -> NIL is legal.
>              (eq 31280938091091 31280938091091) -> NIL is most probable.

CL-USER 7 > (eq 1 1)
T

Though, yes:
CL-USER 8 > (eq 31280938091091 31280938091091)
NIL

> Small problem: (= 'a 'a) --> error *** - =: A is not a number
>                (my=  'a 'a) --> T

Yes, my= is "more permissive"

>> Another, more elegant way of doing this?
> 
> (setf (symbol-function 'my=) (symbol-function 'cl:=))

That misses entirely the point, which is about how to
implement a polyadic function, not about the specifics
of =, though I did pick = because = seemed simple.

>> Did I just fell into the "easy to write inefficient Lisp code" trap ?
> 
> 沒

Sorry, I don't read Chinese :-(

> If you're trying to re-implement Common Lisp, you should read CLHS.

Since you seem to misunderstand what this is about, let me refornulate:

(defmacro poly-apply (binary-op &rest seq)
  `(when (reduce ,binary-op ,seq) t))

Is this the correct "pattern" to define a polyadic function
out of a binary one?

Many thanks
--
JFB
From: Pascal Bourguignon
Subject: Re: my=
Date: 
Message-ID: <877j98a80a.fsf@thalassa.informatimago.com>
verec <·····@mac.com> writes:
> (defmacro poly-apply (binary-op &rest seq)
>   `(when (reduce ,binary-op ,seq) t))
>
> Is this the correct "pattern" to define a polyadic function
> out of a binary one?

The use of REDUCE, basically, yes.

(when ... t) no, since in general the result of a polyadic function won't be T.


But note that one advantage of polyadic functions is to be able to
optimize the operations according to the arguments.
For example:

(defun mult (&rest args)
   (cond ((null args) 1)                           ; neutral
         ((member 0 args :test (function =)) 0)    ; absorber
         (t (reduce (function *)  args))))

Or you could sort the arguments according to their types to do an
integer reduce  on one side, a floating point reduce on another, and a
rational reduce on a third, and only convert for the final operation.

Or you could call: (ALTIVEC-op ...) instead of (REDUCE op ...). Etc.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

COMPONENT EQUIVALENCY NOTICE: The subatomic particles (electrons,
protons, etc.) comprising this product are exactly the same in every
measurable respect as those used in the products of other
manufacturers, and no claim to the contrary may legitimately be
expressed or implied.
From: verec
Subject: Re: my=
Date: 
Message-ID: <43c3d172$0$87297$5a6aecb4@news.aaisp.net.uk>
On 2006-01-10 06:53:41 +0000, Pascal Bourguignon <····@mouse-potato.com> said:

> verec <·····@mac.com> writes:
>> (defmacro poly-apply (binary-op &rest seq)
>> `(when (reduce ,binary-op ,seq) t))
>> 
>> Is this the correct "pattern" to define a polyadic function
>> out of a binary one?
> 
> The use of REDUCE, basically, yes.

Thanks.

> (when ... t) no, since in general the result of a polyadic function won't be T.

I take your point for the general case. Though, for boolean
comparators, the only expected outcome is either t or nil.

So you slashed my hope to get one unique macro. I need
two: poly-comp and poly-op (-:

> But note that one advantage of polyadic functions is to be able to
> optimize the operations according to the arguments.

Arrgh. Now I need more than two!

> (defun mult (&rest args)
>    (cond ((null args) 1)                           ; neutral
>          ((member 0 args :test (function =)) 0)    ; absorber
>          (t (reduce (function *)  args))))

OK. I'll forget about the macros, then )-:

BTW: any reason why you use "(function =)" rather than "#'=" ?

> Or you could sort the arguments according to their types to do an
> integer reduce  on one side, a floating point reduce on another, and a
> rational reduce on a third, and only convert for the final operation.

I see the idea. Thanks.

> Or you could call: (ALTIVEC-op ...) instead of (REDUCE op ...). Etc.

I wish there was an ALTIVEC-op in LW but ... are you also
preparing an SSE3-op for today's announcement at MW? :-)

Many thanks.
--
JFB
From: Pascal Bourguignon
Subject: Re: my=
Date: 
Message-ID: <87u0cc850a.fsf@thalassa.informatimago.com>
verec <·····@mac.com> writes:
> BTW: any reason why you use "(function =)" rather than "#'=" ?

Yes. 1- I prefer parentheses to sharp and quote.
     2- (function x) works in emacs too, not #'x.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

ATTENTION: Despite any other listing of product contents found
herein, the consumer is advised that, in actuality, this product
consists of 99.9999999999% empty space.
From: Johan =?iso-8859-15?Q?Bockg=E5rd?=
Subject: Re: my=
Date: 
Message-ID: <yoijy81ngzva.fsf@iota202.dd.chalmers.se>
Pascal Bourguignon <····@mouse-potato.com> writes:

>      2- (function x) works in emacs too, not #'x.

Untrue.
From: Pascal Bourguignon
Subject: Re: my=
Date: 
Message-ID: <878xtn8gzf.fsf@thalassa.informatimago.com>
············@dd.chalmers.se (Johan Bockg�rd) writes:

> Pascal Bourguignon <····@mouse-potato.com> writes:
>
>>      2- (function x) works in emacs too, not #'x.
>
> Untrue.

It was when it mattered, when I took the habit.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

CONSUMER NOTICE: Because of the "uncertainty principle," it is
impossible for the consumer to simultaneously know both the precise
location and velocity of this product.
From: Thomas F. Burdick
Subject: Re: my=
Date: 
Message-ID: <xcvbqykja2k.fsf@conquest.OCF.Berkeley.EDU>
verec <·····@mac.com> writes:

> On 2006-01-10 04:17:09 +0000, Pascal Bourguignon <····@mouse-potato.com> said:
>
> > Big problem: (eq 1 1) -> NIL is legal.
> >              (eq 31280938091091 31280938091091) -> NIL is most probable.
> 
> CL-USER 7 > (eq 1 1)
> T
> 
> Though, yes:
> CL-USER 8 > (eq 31280938091091 31280938091091)
> NIL
> 
> > Small problem: (= 'a 'a) --> error *** - =: A is not a number
> >                (my=  'a 'a) --> T
> 
> Yes, my= is "more permissive"

No, it's just pretty much wrong:

  (eq (1+ most-positive-fixnum) (1+ most-positive-fixnum)) => nil
  (eq 1 1.0) => nil
  (= 1 1.0) => t

If you want object identity, use EQL (then the bignums will work).  If
you want numeric identity, use = (then the integer/float comparison
will work).  If you want to expose random details of the Lisp
implementation you're running in, use EQ.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kenny Tilton
Subject: Re: my=
Date: 
Message-ID: <XsQwf.54345$Ed.19100@news-wrt-01.rdc-nyc.rr.com>
verec wrote:
> On 2006-01-10 04:17:09 +0000, Pascal Bourguignon <····@mouse-potato.com> 
> said:
> 
>> verec <·····@mac.com> writes:
>>
>>> Speaking of polyadic functions in another thread,
>>> I investigated how I could write my own.
>>>
>>> My goal was to have
>>>
>>> (defun my= (...)
>>>
>>> operate exactly like = does with respect
>>> to both syntax and correctness.
>>>
>>> I came up with:
>>>
>>> 1: (defun my= (&rest list)
>>> 2:   (flet ((bin= (&optional x y)
>>> 3:            (when (eq x y) x)))
>>> 4:     (when (reduce #'bin= list) t)))
>>>
>>>
>>> 1: used &rest to allow (my= 1 2 3) rather than (my= '(1 2 3))
>>> 2: used &optional because reduce calls bin= with either 0 or 2
>>> arguments
>>> 3: used "eq" rather than "=" because x may be nil
>>> 4: added a "when" otherwise the result is (nth n list)
>>> for some value of n, rather than T
>>>
>>> CL-USER 41 > (my= 1 1 2)
>>> NIL
>>> CL-USER 42 > (my= 1 1 1)
>>> T
>>
>> Big problem: (eq 1 1) -> NIL is legal.
>>              (eq 31280938091091 31280938091091) -> NIL is most probable.
> 
> 
> CL-USER 7 > (eq 1 1)
> T

You got lucky. PB's point remains, (eq 1 1) /might/ return NIL and the 
implementation would be justified in doing so, according to the spec. 
Moral: Use EQL on numbers and characters.

kt
From: Don Geddis
Subject: Re: my=
Date: 
Message-ID: <871wzgdlkt.fsf@geddis.org>
verec <·····@mac.com> wrote on Tue, 10 Jan 2006:
> My goal was to have
> (defun my= (...)
> operate exactly like = does with respect
> to both syntax and correctness.
> 1: (defun my= (&rest list)
> 2:   (flet ((bin= (&optional x y)
> 3:            (when (eq x y) x)))
> 4:     (when (reduce #'bin= list) t)))

#'= does a lot more magic on numbers than you seem to have realized.
#'eq is not a substitute.

> 3: used "eq" rather than "=" because x may be nil

Very poor reasoning.  If you want to extend #'= to also handle NIL, you
might be able to do that with a new special case in your #'my= definition.
But using #'eq instead is a mistake.  That in no way is "more general" than
#'=.

> CL-USER 41 > (my= 1 1 2)
> NIL
> CL-USER 42 > (my= 1 1 1)
> T
> Anything I missed?

Yes:

CL-USER> (= 1 1.0)
T
CL-USER> (my= 1 1.0)
NIL

Note also that some people's suggestions on this thread of #'eql instead of
#'eq won't help either:

CL-USER> (eql 1 1.0)
NIL

(BTW: I realize you're more interested in the binary-to-poly part, but you
did say "operate exactly like = does with respect to [...] correctness.")

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               ···@geddis.org
I hope some animal never bores a hole in my head and lays its eggs in my brain,
because later you might think you're having a good idea but it's just eggs
hatching.  -- Deep Thoughts, by Jack Handey [1999]
From: verec
Subject: Re: my=
Date: 
Message-ID: <43c3fd7a$0$87292$5a6aecb4@news.aaisp.net.uk>
On 2006-01-10 17:44:34 +0000, Don Geddis <···@geddis.org> said:

> (BTW: I realize you're more interested in the binary-to-poly part, but you
> did say "operate exactly like = does with respect to [...] correctness.")

Yep. That was poor wording on my part. What I had in mind when
I said "correct" was "considers all the arguments in a suitable
order, and return a result compatible with considering them all".
I didn't have in mind number testing accuracy (eq 1 1.0) or either
of the other counter-examples that others have suggested.

I should probably have chosen my-string= instead :-)
--
JFB
From: Frode Vatvedt Fjeld
Subject: Re: my=
Date: 
Message-ID: <2hk6d8zch5.fsf@vserver.cs.uit.no>
verec <·····@mac.com> writes:

> 1: (defun my= (&rest list)
> 2:   (flet ((bin= (&optional x y)
> 3:            (when (eq x y) x)))
> 4:     (when (reduce #'bin= list) t)))

> Anything I missed? Another, more elegant way of doing this?  Did I
> just fell into the "easy to write inefficient Lisp code" trap ?

Well, eq is a mistake. When you think you want to use eq on numbers,
it's a sign that you've done something wrong. Here I think the problem
is the use of reduce, which doesn't really tackle this particular
problem so well. Also, your function's signature isn't the same as
that of cl:=.

Here's how I'd do it:

  (defun my= (n &rest more)
    (dolist (m more t)
      (unless (= n m)
        (return nil))))

Or perhaps this:

  (defun my= (n &rest more)
    (loop for m in more
       always (= n m))))

or even

  (defun my= (n &rest more)
    (every (lambda (m) (= n m))
           more))


I believe these three functions express the exact same
algortihm. Which, btw, does "early exit" such that e.g.  (my= 1 2 3 3
3 3 3 3 3 3 ...) will only perform a single comparison before
concluding that the result will be false, as opposed to completing all
N-1 binary comparisons.

-- 
Frode Vatvedt Fjeld
From: verec
Subject: Re: my=
Date: 
Message-ID: <43c3cba5$0$87297$5a6aecb4@news.aaisp.net.uk>
On 2006-01-10 08:57:58 +0000, Frode Vatvedt Fjeld <······@cs.uit.no> said:

[...]
> Here's how I'd do it:
> 
>   (defun my= (n &rest more)
>     (dolist (m more t)
>       (unless (= n m)
>         (return nil))))
> 
> Or perhaps this:
> 
>   (defun my= (n &rest more)
>     (loop for m in more
>        always (= n m))))
> 
> or even
> 
>   (defun my= (n &rest more)
>     (every (lambda (m) (= n m))
>            more))
[...]
Excellent! Exactly the kind of comment I was looking
for.

Many thanks.
--
JFB
From: Sam Steingold
Subject: Re: my=
Date: 
Message-ID: <u1wzggcws.fsf@gnu.org>
> * verec <·····@znp.pbz> [2006-01-10 03:51:19 +0000]:
>
> My goal was to have
>
> (defun my= (...)
>
> operate exactly like = does with respect
> to both syntax and correctness.

why not use cl:= then?

one common newbie mistake is to think that CL lacks something fundamental.

(note that I am _not_ saying that CL lacks nothing fundamental - it's
just that finding those things takes expertize).

if you think that you need something as basic as equality, you should
ask yourself if you are indeed doing something so exotic that nobody in
the last 20 years (since CLtL1) or 50 years (since JMC) ever tried.

good luck

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
http://www.palestinefacts.org http://www.dhimmi.com http://www.iris.org.il
http://truepeace.org http://www.mideasttruth.com http://ffii.org
Sinners can repent, but stupid is forever.
From: verec
Subject: Re: my=
Date: 
Message-ID: <43c400e1$0$87292$5a6aecb4@news.aaisp.net.uk>
On 2006-01-10 18:23:31 +0000, Sam Steingold <···@gnu.org> said:

>> * verec <·····@znp.pbz> [2006-01-10 03:51:19 +0000]:
>> 
>> My goal was to have
>> 
>> (defun my= (...)
>> 
>> operate exactly like = does with respect
>> to both syntax and correctness.
> 
> why not use cl:= then?

I'm not sure why people insist on the second paragraph, when
the first said:

> Speaking of polyadic functions in another thread,
> I investigated how I could write my own.

I'm not sure how much more *plain* I can put it that I'm
interested in the mecahnichs of a polyadic function, not
in the particular of any of them.

I have to agree that my chosing of = was poor. Not intrinscially,
but because it led people to mistake the wood for the tree.

Fortunately, I received very interesting, on topic, examples.

My preferred, so far, being

> On 2006-01-10 08:57:58 +0000, Frode Vatvedt Fjeld <······@cs.uit.no> said:

>   (defun my= (n &rest more)
>     (dolist (m more t)
>       (unless (= n m)
>         (return nil))))

>   (defun my= (n &rest more)
>     (loop for m in more
>        always (= n m))))

>   (defun my= (n &rest more)
>     (every (lambda (m) (= n m))
>            more))

Many thanks to all
--
JFB