LISP - 从列表中添加所有原子(任何级别)

时间:2014-11-30 11:17:43

标签: lisp add

我猜这应该是LISP很容易做到的事情(他们之所以这么称呼它),但我无法绕过它。

我们说我有以下列表:

  

((1 2 3)(4(5 6)))

我想将它们全部添加,因此结果应为21

我开始很容易,尝试从一个好的列表中添加元素(如(1 2 3)),我几乎做到了:

(defun sum (list)
    (if list
        (+ (car list) (sum (cdr list)))
    0)
)

可能有更好的编码方式和更好的排列方式,但是现在这种(几乎像C语言)缩进样式可以帮助我跟踪我的括号。它有效。

不幸的是,对于我的示例中的列表来说,它还不够好。所以我再试一次:

(defun sum (list)
    (cond
        ( (atom (car list)) (+ (car list) (sum (cdr list))) )
        ( (list (car list)) (+ (sum (car list) ) (sum (cdr list))))
    )
)

这看起来并不过分,因为即使对于简单的示例我也会出现堆栈溢出错误。

编辑: 我设法写了一个工作(而不是那么复杂)的功能:

(defun sum (l)
  (cond
    ((null l) 0)
    ((atom (car l)) (+ (car l) (sum (cdr l))))
    ((+ (sum (car l)) (sum (cdr l))))
  )
)

2 个答案:

答案 0 :(得分:3)

你说:

  

可能有更好的编码方式和更好的排列方式,但是现在这种(几乎像C语言)缩进样式可以帮助我跟踪我的括号。它有效。

任何现代编辑都会帮助你。编辑器缩进并计算括号。缩进是正确的,这一点非常重要。

格式化Lisp代码的最佳方法是:

(defun sum (list)
  (if list
      (+ (car list)
         (sum (cdr list)))
    0))

编写函数的更好方法是这样的:

(defun sum (list)
  (cond ((null list)         0)                     ; termination test first
        ((atom (first list)) (+ (first list)        ; FIRST not CAR
                                (sum (rest list)))) ; REST  not CDR
        (t                   (+ (sum (first list))
                                (sum (rest list))))))

略有不同的版本:

(defun sum (list)
  (if (null list)                     ; termination test first
      0                               ; termination value
    (destructuring-bind (head . tail) ; bind variables
        list                          ; matching with LIST
      (+ (if (atom head)              ; all list elements are numbers
             head
           (sum head))
         (sum tail)))))

答案 1 :(得分:2)

你非常接近。调整你的第一个变种:

(defun sum (list)
    (if list
        (+ (sum (car list)) (sum (cdr list)))
    0)
)

因为(car list)本身可能是一个列表,不一定是数字。

所以现在我们必须让这个工作,以防 一个数字 - 而且不仅car,而且cdr也是:

(defun sum (list)
    (if (not (listp list))
        ; an obvious result here...
        ...
        ; or else it's a list
        (+ (sum (car list)) (sum (cdr list)))
    0)
)

但是等等,这里确实有三个个案例 - 一个非空列表,一个空列表,而不是一个列表。相应地修改代码。