1
votes

I have this function:

(defun call-generic-function (gf &rest args)
    (let* ((applicable-methods (compute-applicable-methods gf  args))
            (most-specific-method (select-next-method-to-call  
                applicable-methods)))
        (print "applicable methods")
        (print (length applicable-methods))  
        (print args)
        (print (values-list args))
        (funcall (method-function most-specific-method)
              (values-list args)         
              (remove most-specific-method applicable-methods))))

I expect values-list to give me all the elements of the list args (these are two objects to be passed as two out of the three expected arguments to the called method by funcall) but it only gives the first element and I get an error that I am only supplying 2 arguments instead of the expected 3 arguments. This can be confirmed by the fact that (print args) prints a list of 2 objects but (print (values-list args)) prints out just the first of these objects. How can I correct this?

results (print args):

(#S(OBJECT
    :CLASS #S(CLASS
              :DIRECT-SUPERCLASS #S(CLASS
                                    :DIRECT-SUPERCLASS #S(CLASS
                                                          :DIRECT-SUPERCLASS NIL
                                                          :DIRECT-SLOTS NIL)
                                    :DIRECT-SLOTS (NAME ADDRESS))
              :DIRECT-SLOTS (EMPLOYER))
    :SLOTS #<HASH-TABLE :TEST EQL :COUNT 3 {1003932403}>)
 #S(OBJECT
    :CLASS #S(CLASS
              :DIRECT-SUPERCLASS #S(CLASS
                                    :DIRECT-SUPERCLASS NIL
                                    :DIRECT-SLOTS NIL)
              :DIRECT-SLOTS (SPORTS))
    :SLOTS #<HASH-TABLE :TEST EQL :COUNT 1 {1003932853}>)) 

result (print (values-list args))

#S(OBJECT
   :CLASS #S(CLASS
             :DIRECT-SUPERCLASS #S(CLASS
                                   :DIRECT-SUPERCLASS #S(CLASS
                                                         :DIRECT-SUPERCLASS NIL
                                                         :DIRECT-SLOTS NIL)
                                   :DIRECT-SLOTS (NAME ADDRESS))
             :DIRECT-SLOTS (EMPLOYER))
   :SLOTS #<HASH-TABLE :TEST EQL :COUNT 3 {1003932403}>) 

As you can see, values-list gets just the first object and makes my function which expects both objects fail.

1
What did you expect values-list to do?melpomene
For example,(+ (values-list '(1 2))) should give me 3. That is what I thought, but i gives me 1Gakuo
... why would it do that? I don't think + does anything special with multiple-values.melpomene
Shock on me. I saw it at stackoverflow.com/questions/8243813/…. Was thinking I can achieve " (+ (values-list '(1 2))) = 3" with it. What can I use to dynamically retrieve all the elements of a list and pass them to a function as individual elements?Gakuo
I think you want apply, not funcall.melpomene

1 Answers

6
votes

Let’s see what happens with values-list:

CL-USER> (values-list '(1 2 3))
1 ;
2
3

This function takes a list and returns its items as multiple values. The way that multiple values works is that in most situations the multiple values are removed and only the first is used (if no values are returned then NIL is used):

CL-USER> (list (values-list '(1 2 3)))
(1)

There are ways to use multiple values or to call a function with multiple arguments:

CL-USER> (apply #'list 4 '(1 2 3))
(4 1 2 3)
CL-USER> (multiple-value-call #'list (values 4 5) (values-list '(1 2 3)))
(4 5 1 2 3)

Note however that in your question you seem to want to call print with multiple arguments:

CL-USER> (print 1 2)
;; error because 2 is not an output stream

If you want to print each item of the list then you can use a loop or format:

CL-USER> (loop for item in '(1 2 3) do (print item))
1
2
3
NIL
CL-USER> (format t "~{~a~%~}" '(1 2 3))
1
2
3
NIL

If you want to call a function with an arbitrary number of arguments in the middle then:

CL-USER> (apply #'list 1 (append '(1 2) (list 3)))
(1 1 2 3)
CL-USER> (multiple-value-call #'list 1 (values-list '(1 2)) 3)
(1 1 2 3)

But in your case I think the actual solution is to pass the list of applicable methods in the first argument rather than the last.