【问题标题】:LISP - adding all atoms from a list (any level)LISP - 从列表中添加所有原子(任何级别)
【发布时间】:2014-11-30 11:17:42
【问题描述】:

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

【问题讨论】:

  • 这是一个关于如何reduce对树元素的加法函数的问题。我链接到的副本询问如何在树上减少函数并使用加法作为具体示例。
  • @Joshua Taylor 关闭,但我有兴趣在不展平列表的情况下执行此操作(在尝试做其他一些事情时我设法很容易地进行展平)。有趣的链接和例子:)

标签: lisp add


【解决方案1】:

你说:

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

【讨论】:

  • 重新正确缩进,我注意到 Emacs 对 if 形式的 else 分支使用“body-indentation”,但在 Scheme 世界中,缩进 else 分支更常见then 分支(Riastradh 的风格指南支持这一点)。很想听听你对这一切的看法。
  • @ChrisJester-Young:'flush' 版本在 Common Lisp 中也很常见 ;-)。我使用 LispWorks,它的编辑器使用这种风格——尽管它可以进行不同的配置。这种风格也用在 Emacs Lisp 中。 Lisp 机器上的 IIRC,您可以在不同的缩进变体之间循环。
【解决方案2】:

你很亲密。调整您的第一个变体:

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

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

所以现在我们必须让 this 工作,以防它 一个数字 - 不仅是 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)
)

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

【讨论】:

  • 谢谢。我尝试应用您的建议来编辑我的代码,结果非常接近。
猜你喜欢
  • 2016-03-23
  • 2011-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多