为什么这个简单的 LISP 函数会抛出错误?



我将这个函数与一个更大的脚本隔离出来,并通过 https://www.jdoodle.com/execute-clisp-online/运行它。即使抛出了一个错误,它似乎也遵循了 LISP 的规则,除非我错过了一些明显的东西。

(defun cannibals-can-eat (state start-state)
(let ((left-bank-missionaries 2)
(left-bank-cannibals 5)
(right-bank-missionaries (- 3 left-bank-missionaries))
(right-bank-cannibals (- 2 left-bank-cannibals)))
(if (or (> left-bank-cannibals left-bank-missionaries)
(> right-bank-cannibals right-bank-missionaries))
t
nil)))

错误有时The variable LEFT-BANK-MISSIONARIES is unbound.unmatched close parenthesissyntax error near unexpected token(''.对于此版本的函数,错误是后者。

在Common Lisp中,有两种形式的本地声明(let(:

(let ((var1 exp1)
(var2 exp2)
...
(varn expn))
exp)

(let* ((var1 exp1)
(var2 exp2)
...
(varn expn))
exp)

在第一个表达式中,expi的每个表达式都在let之前的环境中进行计算。在第二个表达式中,expi的每个表达式都在包含所有先前声明的环境中计算var1 ... var(i-1)

因此,在您的示例中,right-bank-missionaries的声明使用未定义的left-bank-missionaries,因为它是在同一let中声明的。

只需使用let*即可允许在声明后立即使用每个变量:

(defun cannibals-can-eat (state start-state)
(let* ((left-bank-missionaries 2)
(left-bank-cannibals 5)
(right-bank-missionaries (- 3 left-bank-missionaries))
(right-bank-cannibals (- 2 left-bank-cannibals)))
(or (> left-bank-cannibals left-bank-missionaries)
(> right-bank-cannibals right-bank-missionaries))))

请注意,如果要返回广义布尔值,则最终if毫无用处。

最新更新