From: Oliver Christ
Subject: #'reduce
Date: 
Message-ID: <OLI.92Oct6124657@milan.ims.uni-stuttgart.de>
Hi,

this might be an annoying question, but why does

 (reduce #'max '("This" "is" "a" "test" ".") :key #'length)

result in a 'unknown keyword: :key' error both with Allegro CL 4.1 and
Lucid 4.0 on a Sparc? 

  (find 4 '("This" "is" "a" "test" ".") :key #'length)

(although not very useful) works fine.

Any help? In X3J13's CL draft #'reduce accepts :key arguments.

Thanks,

Oli
--
Oli
---------------------------------------------------------------------------
Oliver Christ
Institute for Natural Language Processing, University of Stuttgart, Germany
···@···························@is.informatik.uni-stuttgart.de
---------------------------------------------------------------------------

From: Danny Brewer
Subject: Re: #'reduce
Date: 
Message-ID: <danny-061092112735@danny.farallon.com>
In article <················@milan.ims.uni-stuttgart.de>,
···@milan.ims.uni-stuttgart.de (Oliver Christ) wrote:
> this might be an annoying question, but why does
> 
>  (reduce #'max '("This" "is" "a" "test" ".") :key #'length)
> 
> result in a 'unknown keyword: :key' error both with Allegro CL 4.1 and
> Lucid 4.0 on a Sparc? 

Reduce doesn't accept :KEY according to CLtL2.  In fact, if you
look at REDUCE more closely, you'll see that :KEY wouldn't make sense.

Instead of REDUCE, try the following:

(APPLY #'MAX (MAPCAR #'LENGTH '("This" "is" "a" "test" ".")))

Even more efficient would be:

(LET ((max 0))
  (DOLIST (elt '("This" "is" "a" "test" "."))
    (SETF max (MAX max (LENGTH elt))))
  max)


Danny Brewer
·····@farallon.com
From: Peter Norvig - Sun BOS SunLabs
Subject: Re: #'reduce
Date: 
Message-ID: <1asmh4INNh5e@seven-up.East.Sun.COM>
In article <················@milan.ims.uni-stuttgart.de>,
···@milan.ims.uni-stuttgart.de (Oliver Christ) wrote:
> this might be an annoying question, but why does
> 
>  (reduce #'max '("This" "is" "a" "test" ".") :key #'length)
> 
> result in a 'unknown keyword: :key' error both with Allegro CL 4.1 and
> Lucid 4.0 on a Sparc? 

Reduce *does* take a :key argument in dpANS Common Lisp (page 17-13),
and in CLtL2 page 398, but not on page 397, which may be why some vendors
have not implemented it.

It makes perfect sense to have a :key argument.  The meaning (and
efficiency in a good implementation) of Oliver's expression above
should be exactly the same as the proposed solution below:

(LET ((max 0))
    (DOLIST (elt '("This" "is" "a" "test" "."))
		(SETF max (MAX max (LENGTH elt))))
    max)

The vendors are perhaps excused because CLtL2 was ambiguous on this, but
any Lisp with ansi-cl or draft-ansi-cl in its *features* list must
implement :key for reduce.  If you don't get it in the next release from
your vendor, complain loudly.

In the meantime, the following implementation, taken from "Paradigms of
AI Programming", implements :key for reduce:

(proclaim '(inline reduce reduce*))

(defun reduce* (fn seq from-end start end key init init-p)
  (funcall (if (listp seq) #'reduce-list #'reduce-vect)
           fn seq from-end (or start 0) end key init init-p))

(defun reduce (function sequence &key from-end start end key
               (initial-value nil initial-value-p))
  (reduce* function sequence from-end start end
           key initial-value initial-value-p))

(defun reduce-vect (fn seq from-end start end key init init-p)
  (if (null end) (setf end (length seq)))
  (assert (<= 0 start end (length seq)) (start end)
          "Illegal subsequence of ~a --- :start ~d :end ~d"
          seq start end)
  (case (- end start)
    (1 (if init-p
           (funcall fn init (funcall-if key (aref seq start)))
           (funcall-if key (aref seq start))))
    (0 (if init-p init (funcall fn)))
    (t (if (not from-end)
           (let ((result
                   (if init-p
                       (funcall
                         fn init
                         (funcall-if key (aref seq start)))
                       (funcall
                         fn
                         (funcall-if key (aref seq start))
                         (funcall-if key (aref seq (+ start 1)))))))
             (loop for i from (+ start (if init-p 1 2))
                   to (- end 1)
                   do (setf result
                            (funcall
                              fn result
                              (funcall-if key (aref seq i)))))
             result)
           (let ((result
                   (if init-p
                       (funcall
                         fn
                         (funcall-if key (aref seq (- end 1)))
                         init)
                       (funcall
                         fn
                         (funcall-if key (aref seq (- end 2)))
                         (funcall-if key (aref seq (- end 1)))))))
             (loop for i from (- end (if init-p 2 3)) downto start
                   do (setf result
                            (funcall
                              fn
                              (funcall-if key (aref seq i))
                              result)))
             result)))))

(defun reduce-list (fn seq from-end start end key init init-p)
  (if (null end) (setf end (length seq)))
  (cond ((> start 0)
         (reduce-list fn (nthcdr start seq) from-end 0
                      (- end start) key init init-p))
        ((or (null seq) (eql start end))
         (if init-p init (funcall fn)))
        ((= (- end start) 1)
         (if init-p
             (funcall fn init (funcall-if key (first seq)))
             (funcall-if key (first seq))))
        (from-end
         (reduce-vect fn (coerce seq 'vector) t start end
                      key init init-p))
        ((null (rest seq))
         (if init-p
             (funcall fn init (funcall-if key (first seq)))
             (funcall-if key (first seq))))
        (t (let ((result
                   (if init-p
                       (funcall
                         fn init
                         (funcall-if key (pop seq)))
                       (funcall
                         fn
                         (funcall-if key (pop seq))
                         (funcall-if key (pop seq))))))
             (if end
                 (loop repeat (- end (if init-p 1 2)) while seq
                    do (setf result
                             (funcall
                               fn result
                               (funcall-if key (pop seq)))))
                 (loop while seq
                    do (setf result
                             (funcall
                               fn result
                               (funcall-if key (pop seq))))))
             result))))
From: Jeff Dalton
Subject: Re: #'reduce
Date: 
Message-ID: <7843@skye.ed.ac.uk>
In article <············@seven-up.East.Sun.COM> ·······@norvig.Eng.Sun.COM (Peter Norvig - Sun BOS SunLabs) writes:

>In the meantime, the following implementation, taken from "Paradigms of
>AI Programming", implements :key for reduce:

Good book.

But while we're here, what is the status of the code in that book?
What are people who read the book allowed to use it for?

More generally, as an author, can you tell me what the usual rules
are for this.  For instance, if I get an algorithms book, can I
use the algorithm as given in the book or do I have to make
gratuitious changes in order to avoid copyright violations?

-- jeff
From: Ozan Yigit
Subject: paip [Re: #'reduce]
Date: 
Message-ID: <OZ.92Nov6120318@ursa.sis.yorku.ca>
Jeff Dalton writes:

   But while we're here, what is the status of the code in that book?
   What are people who read the book allowed to use it for?

He made the code freely available, for ftp. [the scheme repository
has it as well] sources contain a simple copyright, with no gratuituous
restrictions, so I assume you use them just like you use any other
source distributed publically with a copyright. [Peter?]

oz
---
In seeking the unattainable, simplicity | internet: ··@nexus.yorku.ca
only gets in the way. -- Alan J. Perlis | phone: 416 736 2100 x 33976
From: Peter Norvig - Sun BOS SunLabs
Subject: Re: paip copyright restriction
Date: 
Message-ID: <1dek51INN8j9@seven-up.East.Sun.COM>
My understanding and intent is that the copyright on the code has the
same status as the copyright on a book or article: it allows you the
reader to make whatever personal use of it you want, but you can't
sell it without my permission.  (If someone does want to use my code
in a commercial application, I'd be happy to negotiate something.)
It may be that the copyright technically prohibits you from passing on
free copies also, but that was not my intent: I placed the code in a
public place so that it would be used, and if any reader wants to give a
free copy to someone else, you hereby have my permission.

Note that copyright does not cover ideas, only their expression, so if you 
reimplement the code its yours.  Also note that these are my impressions,
with no legal advice, so I could be all wrong.

______________________________________________________________________
Peter Norvig				Tel: (508) 671-0508
Sun Microsystems Laboratories		Fax: (508) 671-0432
Two Federal Street			Email: ············@East.Sun.COM
Billerica MA 01821 USA
______________________________________________________________________
From: Jeff Dalton
Subject: Re: paip copyright restriction
Date: 
Message-ID: <7896@skye.ed.ac.uk>
In article <············@seven-up.East.Sun.COM> ·······@norvig.Eng.Sun.COM (Peter Norvig - Sun BOS SunLabs) writes:
>My understanding and intent is that the copyright on the code has the
>same status as the copyright on a book or article: it allows you the
>reader to make whatever personal use of it you want, but you can't
>sell it without my permission.

I don't mean this as a complaint about your book (which I think is
excellent), but this sort of rule significantly decreases the utility
of books that contain code.  Indeed, I sometimes wonder whether some
of the seemingly gratuitous differences in the presentation of, say,
"streams" in various Lisp texts might be due to a desire to avoid
copyright problems.  (By "streams" I mean lazy lists.)
From: Jeff Dalton
Subject: Re: paip [Re: #'reduce]
Date: 
Message-ID: <7877@skye.ed.ac.uk>
In article <···············@ursa.sis.yorku.ca> ··@ursa.sis.yorku.ca (Ozan Yigit) writes:
>Jeff Dalton writes:
>
>   But while we're here, what is the status of the code in that book?
>   What are people who read the book allowed to use it for?
>
>He made the code freely available, for ftp. [the scheme repository
>has it as well] sources contain a simple copyright, with no gratuituous
>restrictions, so I assume you use them just like you use any other
>source distributed publically with a copyright. [Peter?]

Copyright comes with a bunch of restrictions automatically, though
I'm not sure exactly what they imply for code.  The way things are
going these days, I'd be very cautious about using any copyrighted
code in a commercial product unless very explicit permission was
granted; and I'm not sure academic use is any less restricted
(it's just that the consequences of things going wrong are probably
less).

But I don't really know what the rules are for books that contain
code.  For instance, if I look up an algorithm in a book, can I
use the code in the book as-is or do I have to make gratuitous
changes or what?

-- jeff
From: Clinton Hyde
Subject: Re: #'reduce
Date: 
Message-ID: <CHYDE.92Oct7135331@pecos.ads.com>
Reduce in Steele-1 doesn't allow :key. in Steele-2 it does. but that
may not have been implemented at all.

(apply #'max (mapcar #'length list)) is a marginal substitute, since
REDUCE should work on Any Sequence.

 -- clint
--

Clint Hyde		"Give me a LispM or give me death!" -- anonymous

Advanced Decision Systems/BAH	Internet:  ·····@chesapeake.ads.com
1953 Gallows Rd, Suite 600
Vienna, VA  22182-3934		(703) 902-7130
From: Mark A. Tapia
Subject: Re: #'reduce
Date: 
Message-ID: <1992Oct8.163405.26083@jarvis.csri.toronto.edu>
In article <··················@danny.farallon.com> ·····@farallon.com 
(Danny Brewster) writes in response to  <················@milan.ims.
uni-stuttgart.de>, (Oliver Christ) about the program fragment:
>>  (reduce #'max '("This" "is" "a" "test" ".") :key #'length)
>> 
>
>Reduce doesn't accept :KEY according to CLtL2.  In fact, if you
>look at REDUCE more closely, you'll see that :KEY wouldn't make sense.
>
>Instead of REDUCE, try the following:
>
>(APPLY #'MAX (MAPCAR #'LENGTH '("This" "is" "a" "test" ".")))
>
>Even more efficient would be:
>
>(LET ((max 0))
>  (DOLIST (elt '("This" "is" "a" "test" "."))
>    (SETF max (MAX max (LENGTH elt))))
>  max)
>

Macintosh Common Lisp (MCL) accepts the :key keyword parameter:
? (reduce #'max '("This" "is" "a" "test" ".") :key #'length)
4

You can also use loop to make it clearer:
? (loop for el in '("This" "is" "a" "test" ".")
	maximizing (length el))
4
From: Len Charest
Subject: Re: #'reduce
Date: 
Message-ID: <1992Oct7.184503.21537@jpl-devvax.jpl.nasa.gov>
In article <················@milan.ims.uni-stuttgart.de>, ···@milan.ims.uni-stuttgart.de (Oliver Christ) writes:
|> ... why does
|>  (reduce #'max '("This" "is" "a" "test" ".") :key #'length)
|> result in a 'unknown keyword: :key' error both with Allegro CL 4.1 and
|> Lucid 4.0 on a Sparc? 

|> Any help? In X3J13's CL draft #'reduce accepts :key arguments.

The :KEY argument to REDUCE was added by X3J13. The Lisp implementations you
mention were released prior to the proposed ANSI standard.
..................................................
                                  Len Charest, Jr.
                 JPL Artificial Intelligence Group
                          ·······@aig.jpl.nasa.gov