Search code examples
lispcommon-lispapplymap-function

Arguments to APPLY in Lisp


I am having the following trouble: when trying to use APPLY function with a MAPCAR call, the lambda function passed to APPLY, which contains only one parameter, the list returned by MAPCAR, gives the following error : *** - EVAL/APPLY: too many arguments given to :LAMBDA

The following code identifies if a heterogenous list has the last atom at any level a numerical atom.

(DEFUN hasLastNumeric (L)
  (COND
   ((NUMBERP L) T)
   ((ATOM L) NIL)
   ((LISTP L)
    (APPLY #'(LAMBDA (Lst)
                     (COND ((EQ (LAST Lst) T) T)
                           (T NIL)))
           (MAPCAR 'hasLastNumeric L)))))

(WRITE (hasLastNumeric '(1 2 5)))

Solution

  • If you call a function eg. (#'(lambda (a b) (+ a b)) 2 3) there is a requirement that the number of arguments fits the number of provided arguments. When using apply the requirements are the same so (apply #'(lambda (one) ...) lst) require that lst is only one element list like '(a), but it cannot be '() or '(a b). The only way to support variable number of arguments you need to use &rest arguments eg. (apply #'(lambda (&rest lst) ...) '(a b))

    Looking at the logic I don't understand it. You want to return t when you have encountered a list with the last element as a number but also searched list elements on the way and returned early had you found them. It should be possible without the use of last at each step. eg.

    (defun has-a-last-numeric (lst)
      (labels ((helper (lst)
                 (loop :for (e . rest) :on lst
                       :if (and (null rest) (numberp e))
                           :do (return-from has-a-last-numeric t)
                       :if (listp e)
                           :do (helper e))))
        (helper lst)))