【问题标题】:Why does this simple LISP function throw an error?为什么这个简单的 LISP 函数会抛出错误?
【发布时间】:2019-12-07 06:32:07
【问题描述】:

我将这个函数从一个更大的脚本中分离出来,并通过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('`。在这个版本的函数中,错误是后者。

【问题讨论】:

  • 我唯一能想到的是let函数不会让你使用你声明的变量来声明另一个变量,即使它是后续的。
  • 你可能想阅读let vs let*

标签: syntax-error lisp common-lisp clisp


【解决方案1】:

在 Common Lisp 中有两种形式的局部声明 (let):

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

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

首先,每个表达式expilet 之前的环境中进行评估。在第二个中,每个表达式 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))))

请注意,如果您想返回 generalized boolean,最后的 if 是没有用的。

【讨论】:

    猜你喜欢
    • 2021-02-05
    • 1970-01-01
    • 2015-04-25
    • 2019-09-01
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多