【问题标题】:can anyone explain to me why this lisp code doesn't work?谁能向我解释为什么这个 lisp 代码不起作用?
【发布时间】:2021-06-06 21:58:23
【问题描述】:

它应该计算列表的元素,但显示“*** - +:NIL 不是数字”

(setq A '(2 3 4 3 2 6 7 8 4 3 5 6))

(defun big (A) 
   (if (not (null (car A)))   (+ 1 (big (cdr A)))  )   ;if the first element is not null, add 1 to the count of the elements to the rest of the list
)     
 
(print (big A))

【问题讨论】:

  • 您是否使用在线解释器来评估 Lisp 代码?你的设置是什么?

标签: lisp common-lisp


【解决方案1】:

类型错误

IF 表达式有 2 个或 3 个参数:

(if test something)

(if test something something-else)

当它只有 2 个参数时,就好像第三个参数 something-else 为 NIL。这意味着当test 表达式为假时,IF 表达式的计算结果为 NIL。在您的情况下,您有 2 个参数:

(defun big (A) 
  (if (not (null (car A)))
      ;; "then" branch (when condition is true)
      (+ 1 (big (cdr A)))
      ;; no "else" branch (when condition is false)
      ))

所以您知道,有时调用big 可能会返回NIL

但是,你也写:

(+ 1 (big (cdr A)))

这个表达式看起来像(+ 1 x),其中x 是对big 的调用,这意味着x 在某些情况下可能评估为NIL。这就是您使用调试器遇到的情况。

如果您确保 if 表达式始终返回一个数字,例如在 else 分支中返回零,那么您在尝试将数字添加到 NIL 时不会遇到同样的错误。

计数元素

但是,您仍然会有其他错误,因为您说函数big “应该计算列表的元素”。如果你想计算一个列表的元素,你永远不需要查看列表中存储的元素,你只需要知道它们存在。

当您编写(car a) 时,您正在访问列表的第一个元素。然后检查该值是否为非 nil,但使用 NIL 值填充列表是完全有效的:

'(NIL NIL NIL)

该列表包含 3 个元素,在计算它们时,它们是 NIL 的事实在任何时候都不重要。

处理列表的递归函数通常需要涵盖两种情况,即列表是否为空。您可以通过调用 (null list)(endp list) 来检查当前列表是否为空(只需执行 (if list ... ...) 也可以,因为 NIL 是唯一的错误值)。

【讨论】:

    【解决方案2】:

    对 null car 的测试没有任何好处,cdr 会在 car 之前返回 nil。

    你需要一个基本情况,你发现你已经完成并返回一些东西而不是递归。现在你没有那个。查看简单递归函数的示例,了解它们如何具有基本情况。

    要计算列表中的元素有两种情况:

    列表为空的基本情况(返回 0)

    列表不为空的递归情况(返回 1 + 传入列表的 cdr 计数)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-04
      • 1970-01-01
      • 2011-02-11
      • 2021-04-10
      • 2013-10-22
      • 1970-01-01
      • 2018-11-30
      • 1970-01-01
      相关资源
      最近更新 更多