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

LISP-从列表中添加所有原子(任意级别),lisp,add,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的)缩进

我猜这应该是用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))))
  )
)

你很接近。调整您的第一个变体:

(defun sum (list)
    (if list
        (+ (sum (car list)) (sum (cdr list)))
    0)
)
因为
(汽车列表)
本身可能是一个列表,而不一定是一个数字

因此,现在我们必须使这项工作起作用,以防它是一个数字-不仅是
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)
)

但是等等,这里确实有三种情况——非空列表、空列表和非列表。相应地修改代码。

你很接近了。调整您的第一个变体:

(defun sum (list)
    (if list
        (+ (sum (car list)) (sum (cdr list)))
    0)
)
因为
(汽车列表)
本身可能是一个列表,而不一定是一个数字

因此,现在我们必须使这项工作起作用,以防它是一个数字-不仅是
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)
)
但是等等,这里确实有三种情况——非空列表、空列表和非列表。相应地修改代码。

您说过:

也许有更好的编码方式和更好的排列方式,但现在这种(几乎类似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 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)))))
你说:

也许有更好的编码方式和更好的排列方式,但现在这种(几乎类似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 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)))))

谢谢我尝试应用你的建议编辑了我的代码,结果非常接近。谢谢。我试图应用你的建议编辑了我的代码,结果非常接近。可能的重复是如何减少树元素上的加法函数的问题。我链接到的副本询问如何减少树上的函数,并使用加法作为一个具体示例。@Joshua Taylor close,但我对在不展平列表的情况下进行此操作感兴趣(我在尝试做其他事情时,很容易做到展平)。有趣的链接和示例:)@user3002428扁平化只是随着
append
[]
而减少,因为求和随着
+
0
而减少。这可能重复的问题是如何减少树元素上的加法函数。我链接到的副本询问如何减少树上的函数,并使用加法作为一个具体示例。@Joshua Taylor close,但我对在不展平列表的情况下进行此操作感兴趣(我在尝试做其他事情时,很容易做到展平)。有趣的链接和示例:)@user3002428扁平化只是随着
append
[]
而减少,因为求和随着
+
0
而减少。重新更正缩进,我注意到Emacs对
if
表单的else分支使用了“body indentation”,但在Scheme世界中,将else分支缩进与then分支齐平更为常见(Riastradh的样式指南支持这一点)。渴望听到你对这一切的想法。@ChrisJester-Young:“同花顺”版本很常见;-)在公共Lisp中,也是。我使用LispWorks,它的编辑器使用这种样式——尽管可以进行不同的配置。此样式也用于Emacs Lisp。在Lisp机器上,您可以在不同的缩进变量之间循环。重新更正缩进,我注意到Emacs对
if
表单的else分支使用“body indentation”,但在Scheme世界中,将else分支缩进与then分支齐平(Riastrah的样式指南支持这一点)。渴望听到你对这一切的想法。@ChrisJester-Young:“同花顺”版本很常见;-)在公共Lisp中,也是。我使用LispWorks,它的编辑器使用这种样式——尽管可以进行不同的配置。此样式也用于Emacs Lisp。在Lisp机器上,您可以在不同的缩进变体之间循环。