From: Bruce Feist
Subject: Simple Problem, Hard Solution
Date: 
Message-ID: <732860451.AA00000@blkcat.UUCP>
Hello, everyone!

I have a problem in Common LISP which I have found a solution to, but I'm
convinced that a better one exists.

I have a function -- let's call it x -- which expects two parameters, a and b. 
I also have a list, c; I want to call x once for each element of c, using the
element as the first parameter and b as the second, and return the results as a
list.

In other words, I want to do something almost exactly like a mapcar here -- but
mapcar wants lists for *all* of the parameters, not just the first.

Let me give an example -- I'm starting to get too abstract for my tastes here.
This isn't really what I was trying to do, but it's close enough.  Let's say
that x = +, and I want to write a function to add each element of the first
parameter (a list of numbers) to the second parameter (a number) and return the
results as a list of numbers.

(mapcar #'+ list num) won't work, because num isn't a list.  I tried something
like:

(defun addlist (list num)
  (mapcar #'(lambda (x) (+ x num)) list) )

  but that failed, complaining that 'num' was unbound within the lambda
expression. I assume that what happened there was that I wanted dynamic binding
for num, and was getting lexical.  So, I tried the above, with a defvar num
before the mapcar; I ran for a while, ran out of space, and crashed.  I don't
understand defvar well enough to know why.

My final solution, which I think was pretty clever but still don't like <g>, was
to define an extra function, encircle, which returns a circular list containing
an infinite supply of its argument:

(defun encircle (x &aux result)
  (setq result (list x))
  (replcd result result) )

and then define addlist as

(defun addlist (list num)
  (mapcar #'+ list (encircle num)) )

  thereby taking advantage of mapcar's ability to stop when the end of its
shortest parameter list is reached.

Is there a better solution?

Thanks,
Bruce

From: Espen J. Vestre
Subject: Re: Simple Problem, Hard Solution
Date: 
Message-ID: <1omjviINN7sq@coli-gate.coli.uni-sb.de>
In article <·················@blkcat.UUCP> Bruce Feist,
···········@f615.n109.z1.fidonet.org writes:
> Let me give an example -- I'm starting to get too abstract for my
tastes here.
> This isn't really what I was trying to do, but it's close enough. 
Let's say
> that x = +, and I want to write a function to add each element of the
first
> parameter (a list of numbers) to the second parameter (a number) and
return the
> results as a list of numbers.
> 
> (mapcar #'+ list num) won't work, because num isn't a list.  I tried
something
> like:
> 
> (defun addlist (list num)
>   (mapcar #'(lambda (x) (+ x num)) list) )
> 
>   but that failed, complaining that 'num' was unbound within the lambda
> expression. I assume that what happened there was that I wanted dynamic
binding
> for num, and was getting lexical. So, I tried the above, with a defvar
num
> before the mapcar; I ran for a while, ran out of space, and crashed.  I
don't
> understand defvar well enough to know why.

You _do_ want the lexical binding.

Your function ADDLIST is the standard Common Lisp solution to the problem
you state.  Either you made a typo (in the quoted code there's no typo,
it works fine for me), or your lisp implementation has _severe_ faults.  

(_Maybe_ it (wrongly) gets confused by the use of the formal parameter
"list".  It's generally a bad idea to use built-in symbols of the CL
package in user programs, but since this symbol has no global variable or
constant definition, you should be allowed to use it as a lexical
variable (see CLtLII, p. 260-261).)

________________________________________________________________________
 Espen J. Vestre,                                  ·····@coli.uni-sb.de 
 Universitaet des Saarlandes,                                         
 Computerlinguistik, Gebaeude 17.2                                    
 Im Stadtwald,                                  tel. +49 (681) 302 4501 
 D-6600 SAARBRUECKEN, Germany                   fax. +49 (681) 302 4351
From: Bruno Haible
Subject: built-in symbols
Date: 
Message-ID: <1onsni$lhj@nz12.rz.uni-karlsruhe.de>
Espen J. Vestre writes:
> _Maybe_ it (wrongly) gets confused by the use of the formal parameter
> "list".  It's generally a bad idea to use built-in symbols of the CL
> package in user programs, but since this symbol has no global variable or
> constant definition, you should be allowed to use it as a lexical
> variable (see CLtLII, p. 260-261).

p. 260 is not very clear. What does dpANS specify: Is the symbol
COMMON-LISP:LIST allowed as a (lexical or dynamic) variable despite it
being both a built-in function and a built-in type/class name?


                    Bruno Haible
                    ······@ma2s2.mathematik.uni-karlsruhe.de
From: Barry Margolin
Subject: Re: built-in symbols
Date: 
Message-ID: <1oorc9INNrlv@early-bird.think.com>
In article <··········@nz12.rz.uni-karlsruhe.de> ······@ma2s2.uucp (Bruno Haible) writes:
>p. 260 is not very clear. What does dpANS specify: Is the symbol
>COMMON-LISP:LIST allowed as a (lexical or dynamic) variable despite it
>being both a built-in function and a built-in type/class name?

You can bind it as a lexical variable.  You cannot proclaim it SPECIAL,
neither explicitly with a PROCLAIM or DECLAIM form, nor implicitly with a
DEFVAR, DEFPARAMETER, or DEFCONST.

The intent of the rules on p.260 is to keep unrelated programs from
interfering with each other when loaded into the same Lisp environment.
The COMMON-LISP package is a shared resource, so you shouldn't make
globally-visible changes to it.  For instance, if one program proclaimed
LIST special this would affect other programs that try to use it as a
lexical variable.  For other symbols, the package system keeps unrelated
programs from stepping on each others' toes, since they're assumed to be
using separate packages.

-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Mike Haynie
Subject: Re: built-in symbols
Date: 
Message-ID: <MBH.93Mar24100651@wisdom.wisdom.attmail.com>
In article <··········@nz12.rz.uni-karlsruhe.de> ······@ma2s2.uucp (Bruno Haible) writes:

   Espen J. Vestre writes:
   > _Maybe_ it (wrongly) gets confused by the use of the formal parameter
   > "list".  [...]

   p. 260 is not very clear. What does dpANS specify: Is the symbol
   COMMON-LISP:LIST allowed as a (lexical or dynamic) variable despite it
   being both a built-in function and a built-in type/class name?


		       Bruno Haible
		       ······@ma2s2.mathematik.uni-karlsruhe.de

I would be really puzzled if 

	(defun foo (list) (do some stuff with list))
and
	(defun foo (bar) (do some stuff with bar))

weren't equivalent. Even though LIST is a function, and a type, it is
*still* a symbol with a value cell, and is neither special, nor a
global variable. As an ordinary symbol, it is allowed to be a
parameter, and it is allowed to have a dynamic value.

the dpANS covers this on page 11-5: <>=italics, []=boldface.

	... It also follows that <conforming programs> can use
	<external symbols> of the [COMMON-LISP] <package> as the
	<names> of local <lexical variables> with confidence that
	those <names> have not been <proclaimed> [special] by the
	<implementation> unless those <symbols> are <names> of
	<standardized global variables>.

LIST is not a <standardized global variables>. (whew! ;-)

--

                                ____/|
Michael Haynie                  \ o.O|   ACK!
···@wisdom.attmail.com           =(_)=  THPHTH!
                                   U
From: Flemming Vestergaard
Subject: Re: Simple Problem, Hard Solution
Date: 
Message-ID: <C4CEpM.Jqv@stl.dk>
In <·················@blkcat.UUCP> ···········@f615.n109.z1.fidonet.org (Bruce Feist) writes:

>(defun addlist (list num)
>  (mapcar #'(lambda (x) (+ x num)) list) )

>  but that failed, complaining that 'num' was unbound within the lambda
>expression.

I haven't been programming CL for some years, so I may be wrong, but this
should work, shouldn't it. Is it a Common Lisp compiler? 

- Flemming
From: John R. Gersh
Subject: Re: Simple Problem, Hard Solution
Date: 
Message-ID: <1993Mar23.141656.24302@aplcen.apl.jhu.edu>
In article <·················@blkcat.UUCP> Bruce Feist writes:

	[Wanting to, e.g. add a number to each element of a list]

>
>(mapcar #'+ list num) won't work, because num isn't a list.  I tried something
>like:
>
>(defun addlist (list num)
>  (mapcar #'(lambda (x) (+ x num)) list) )
>
>  but that failed, complaining that 'num' was unbound within the lambda
>expression. 

	As others have noted, this is the usual answer, and ought to
	work.


>My final solution, which I think was pretty clever but still don't like <g>, 
>was to define an extra function, encircle, which returns a circular list 
>containing an infinite supply of its argument:
>
>(defun encircle (x &aux result)
>  (setq result (list x))
>  (replcd result result) )
>
>and then define addlist as
>
>(defun addlist (list num)
>  (mapcar #'+ list (encircle num)) )

Just a historical note, on the "there's nothing new under the sun"
theme:

From my Lisp Machine Manual (Chine Nual), 1984 LMI edition:

circular-list &rest args

	Constructs a circular list whose elements are args, repeated
	infinitely. circular-list is the same as list except that the
	list itself is used as the last cdr, instead of nil.
	circular-list is especially useful with mapcar, as in the
	expression
		(mapcar (function +) foo (circular-list 5))
	which adds each element of foo to 5.

So at least at one time in pre-CL days Bruce's alternative solution
was an accepted method of providing atoms as arguments to mapcar. Why
did things change? A general concern that circular lists are bad
things to accumulate?



---------------------------------------------------------------------
John Gersh                                      ··········@jhuapl.edu
The Johns Hopkins University Applied Physics Laboratory
Johns Hopkins Rd., Laurel, MD 20723		       (301) 953-5503
From: Barry Margolin
Subject: Re: Simple Problem, Hard Solution
Date: 
Message-ID: <1oo5kpINNd8k@early-bird.think.com>
In article <······················@aplcen.apl.jhu.edu> ·····@aplpy.jhuapl.edu (John R. Gersh) writes:
>So at least at one time in pre-CL days Bruce's alternative solution
>was an accepted method of providing atoms as arguments to mapcar. Why
>did things change? A general concern that circular lists are bad
>things to accumulate?

The CIRCULAR-LIST solution predates lexical scoping.  Once lexical scoping
was adopted, it was no longer necessary to use the circular list kludge, as
you could use the more clear lambda expression solution.
-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Richard Fateman
Subject: Circular lists was: Re: Simple Problem, Hard Solution
Date: 
Message-ID: <1oobb9$lg@agate.berkeley.edu>
There are uses for circular lists ..
Here's one ...

Say you want to count mod 5.
You could have a list L (0 1 2 3 4 0 1 2 3 ...)

So instead of using in some loop
   (setf k (mod (1+ k) 5))
you can do
   (setf k (car L))
   (setf L (cdr L))

This may not be an entirely clear win, but consider instead
stepping through permutations or some other repeating list.
The cost for computing the next permutation is harder than
one car and one cdr.


-- 
Richard J. Fateman
·······@cs.berkeley.edu   510 642-1879
From: Mike Haynie
Subject: Re: Simple Problem, Hard Solution
Date: 
Message-ID: <MBH.93Mar23092541@wisdom.wisdom.attmail.com>
In article <·················@blkcat.UUCP> ···········@f615.n109.z1.fidonet.org (Bruce Feist) writes:

Assuming Common LISP for lack of better information ---

	[...]

   (defun addlist (list num)
     (mapcar #'(lambda (x) (+ x num)) list) )

What LISP are you using? The above is a perfectly valid closure
construction. If it doesn't work, then there is a bug in your LISP. :-|

     but that failed, complaining that 'num' was unbound within the lambda
   expression. I assume that what happened there was that I wanted dynamic binding
   for num, and was getting lexical.  So, I tried the above, with a defvar num
   before the mapcar; I ran for a while, ran out of space, and crashed.  I don't
   understand defvar well enough to know why.

*very* buggy...

   My final solution, which I think was pretty clever but still don't like <g>, was
   to define an extra function, encircle, which returns a circular list containing
   an infinite supply of its argument:

   (defun encircle (x &aux result)
     (setq result (list x))
     (replcd result result) )

   and then define addlist as

   (defun addlist (list num)
     (mapcar #'+ list (encircle num)) )

     thereby taking advantage of mapcar's ability to stop when the end of its
   shortest parameter list is reached.

   Is there a better solution?

Given that the above fails, I don't expect this to work, but you can
try...

(defun f1 (list num)
  (loop for n in list
	collect (+ n num)))

   Thanks,
   Bruce

--

                                ____/|
Michael Haynie                  \ o.O|   ACK!
···@wisdom.attmail.com           =(_)=  THPHTH!
                                   U
From: Richard A. O'Keefe
Subject: Re: Simple Problem, Hard Solution
Date: 
Message-ID: <17297@goanna.cs.rmit.oz.au>
In article <·················@blkcat.UUCP>, ···········@f615.n109.z1.fidonet.org (Bruce Feist) writes:
> (defun addlist (list num)
>   (mapcar #'(lambda (x) (+ x num)) list) )

Works as written in AKCL and Poplog Common Lisp.  Which Lisp rejected it?
The Scheme equivalent
	(define (addlist list num)
	    (map (lambda (x) (+ x num)) list))
is also required to work.

It's generally a good idea to use names that are a little bit more
informative than "list".  It's a list of numbers, so
	(defun addlist (Numbers Offset)
	    (mapcar #'(lambda (Number) (+ Number Offset)) Numbers))
helps.

Some functional programming languages have something called
"list comprehension", where one would write
	addlist list num = [x+num | x<-list];
People who are used to that sometimes find the loop macro helpful,
but it wasn't in CLtL1.