0

I need to create a recursive method in LISP that takes the numbers in a list and finds the sum. Anything in the list that is not a number is skipped (For example, if the list contains "Cheese 12 Dog 8 Shoe 5", the output would be 25).

Right now my code finds the sum, but throws an error if there is anything in the list that is not a number. What can be changed to fix that?

(defun adder (lis)
   (cond
    ((null lis) 0)
    (t (eval (cons '+ lis)) )
  )
)
4

2 回答 2

2

This would do:

(defun adder (lis)
  (if (null lis)
    0
    (let ((c (car lis)))
      (if (numberp c)
        (+ c (adder (cdr lis)))
        (adder (cdr lis))))))

Your version is not recursive (you don't call adder inside of adder), maybe you meant something like this (which is non-recursive)?

(defun adder (lis)
  (apply '+ (remove-if-not 'numberp lis)))
于 2013-11-12T18:19:45.053 回答
2

Using apply on lists that can be long is a bit dangerous. If the list is longer than call-arguments-limit, then (apply '+ list) won't work. Now, call-arguments-limit is typically pretty big in modern Lisps, but it's allowed to be as small as 50. For more information about this, see:

I think your best bet would be to use reduce '+ list with a key function that takes each number to itself and each non-number to 0. (This key function is what abiessu mentioned in a comment.)

(reduce '+ list :key (lambda (x) (if (numberp x) x 0)))
CL-USER> (let ((list '(cheese 12 dog 8 shoe 5)))
           (reduce '+ list :key (lambda (x) (if (numberp x) x 0))))
25
CL-USER> (let ((list '()))
           (reduce '+ list :key (lambda (x) (if (numberp x) x 0))))
0

Instead of using a more complex key function, you could also use (remove-if-not 'numberp list) to get rid of the non-numbers (or (remove-if (complement 'numberp) list)):

CL-USER> (let ((list '(cheese 12 dog 8 shoe 5)))
           (reduce '+ (remove-if-not 'numberp list)))
25
CL-USER> (let ((list '()))
           (reduce '+ (remove-if-not 'numberp list)))
0
于 2013-11-12T18:33:30.277 回答