为什么这个简单的 LISP 函数会抛出错误?
Why does this simple LISP function throw an error?
我将这个函数从一个更大的脚本中分离出来,运行 通过 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 parenthesis
或 syntax 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
如果你想return一个generalized boolean是没用的。
我将这个函数从一个更大的脚本中分离出来,运行 通过 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 parenthesis
或 syntax 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
如果你想return一个generalized boolean是没用的。