From: Bernard Tatin
Subject: Q about mapcar
Date: 
Message-ID: <89061n$5sh$1@isis.univ-orleans.fr>
Salut,

I am a Lisp beginer.

I'd like to do something like that :

(defclass laclasse ()
  ((list-of-float :initarg :list-of-float
   :initform ()
   :accessor list-of-float)
   (x1           :initarg :x1
   :initform 2.0
   :accessor x1
   :type float)
   (x2           :initarg :x2
   :initform 3.0
   :accessor x2
   :type float)
   ))

(defmethod compute-x ((c laclasse) (t float))
  (+ (* t (x1 c)) (x2 c))
)

(defmethod compute-all ((c laclasse))
  (setf (list-of-float c) (mapcar #'compute-x c (list-of-float c)))
)

compute-all does not work as expected, I think just because mapcar wants a 1
argument function.

What can I do ?

Bernard Tatin

From: Thomas A. Russ
Subject: Re: Q about mapcar
Date: 
Message-ID: <ymivh3fyb1i.fsf@sevak.isi.edu>
"Bernard Tatin" <·············@univ-orleans.fr> writes:

> I am a Lisp beginer.

Bienvenue!

> I'd like to do something like that :
...

> (defmethod compute-all ((c laclasse))
>   (setf (list-of-float c) (mapcar #'compute-x c (list-of-float c)))
> )
> 
> compute-all does not work as expected, I think just because mapcar wants a 1
> argument function.

The problem that you are running into is that mapcar wants LISTs of the
arguments to the mapping function.  In most cases, the argument lists
should be the same size, although mapcar can handle different length
lists -- it just iterates over the smaller list:

   (mapcar #'+ '(1 2 3 4 5) '(1 1 1))  =>  (2 3 4)

In your call, you have a single object c instead of a list.  That will
break the code.

> What can I do ?

There are two possibilities.  The simplest and most efficient would be
to use an anonymous function (a lambda expression) which will capture
the value of the free variable c (this is called making a closure):

(defmethod compute-all ((c laclasse))
  (setf (list-of-float c) 
        (mapcar #'(lambda (f) (compute-x c f))
                (list-of-float c))))

Now this has the effect of producing a function of one variable, but
mapcar could handle more than just this one.

 *** You can stop reading now ***

A fancier solution (which I don't actually recommend using) would be to
make an appropriate list for the first argument.  This is clever
(obscure?) in that it creates a circular list for the first argument
(effectively an infinitely long list) and relies on mapcar stopping
after it exhausts the finite list.

(Note that if you want to try this by typing in the Lisp listener, make
 sure you set *print-circle* to T so that the listener doesn't crash
 trying to print a circular data structure)

(defmethod compute-all ((c laclasse))
  (let ((list-of-c (list c)))          ;; Make a list.
    (setf (cdr list-of-c) list-of-c)   ;; Make it circular.
    (setf (list-of-float c) 
        (mapcar #'compute-x list-of-c (list-of-float c)))))


-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu    
From: Raymond Wiker
Subject: Re: Q about mapcar
Date: 
Message-ID: <87r9e4uryg.fsf@foobar.orion.no>
"Bernard Tatin" <·············@univ-orleans.fr> writes:

> Salut,
> 
> I am a Lisp beginer.
> 
> I'd like to do something like that :
> 
> (defclass laclasse ()
>   ((list-of-float :initarg :list-of-float
>    :initform ()
>    :accessor list-of-float)
>    (x1           :initarg :x1
>    :initform 2.0
>    :accessor x1
>    :type float)
>    (x2           :initarg :x2
>    :initform 3.0
>    :accessor x2
>    :type float)
>    ))
> 
> (defmethod compute-x ((c laclasse) (t float))
>   (+ (* t (x1 c)) (x2 c))
> )

       Seems you're redefining t, here... not a good idea :-)

> (defmethod compute-all ((c laclasse))
>   (setf (list-of-float c) (mapcar #'compute-x c (list-of-float c)))
> )
> 
> compute-all does not work as expected, I think just because mapcar wants a 1
> argument function.
> 
> What can I do ?

        mapcar wants an n-argument function, where n equals the number
of lists passed to it. If you want to pass other arguments to the
function, you could use a closure:

(defmethod compute-all ((c laclasse))
  (setf (list-of-float c)
        (mapcar #'(lambda (f)
                    (compute-x c f)) ; c comes from enclosing scope
                (list-of-float c))))
        
-- 
Raymond Wiker, Orion Systems AS
+47 370 61150
From: Axel Schairer
Subject: Re: Q about mapcar
Date: 
Message-ID: <fm9aeksrxt2.fsf@methven.dai.ed.ac.uk>
"Bernard Tatin" <·············@univ-orleans.fr> writes:
> (defmethod compute-x ((c laclasse) (t float))
>   (+ (* t (x1 c)) (x2 c))
> )
> 
> (defmethod compute-all ((c laclasse))
>   (setf (list-of-float c) (mapcar #'compute-x c (list-of-float c)))
> )
> 
> compute-all does not work as expected, I think just because mapcar wants a 1
> argument function.

Wrap it into a #'(LAMBDA ...) [has been answered in more detail in
another post already].

Also, the name T of your second formal argument to COMPUTE-X is
problematic: T is a constant and cannot be bound.  Use another name
there.

Cheers,
Axel
From: Tim Bradshaw
Subject: Re: Q about mapcar
Date: 
Message-ID: <ey3900cb2pu.fsf@cley.com>
* Bernard Tatin wrote:

> compute-all does not work as expected, I think just because mapcar wants a 1
> argument function.

I'm assuming (from the defclass...) that this isn't homework.

You want to do something like this:


	(defmethod compute-all ((c ...))
	  ...
	  (mapcar #'(lambda (x)
		      (compute-x c x)) ...)
	  ...)

(Note your definition of COMPUTE-X won't work because you have an
argument called T.)

--tim
From: Bernard Tatin
Subject: Re: Q about mapcar
Date: 
Message-ID: <89df74$iv0$1@isis.univ-orleans.fr>
(late) thanks to all of you ! Now, it works with the lambda function.

Bernard Tatin.