【问题标题】:Lisp warning: xx is neither declared nor bound, it will be treated as if it were declared SPECIALLisp 警告:xx 既未声明也未绑定,将被视为已声明为 SPECIAL
【发布时间】:2010-11-25 23:48:33
【问题描述】:

我是 lisp 的新手,正在编写一些简单的程序来熟悉它。我正在做的一件事是编写阶乘方法的递归和迭代版本。但是,我遇到了一个问题,似乎无法解决。

我在 Lisp: CHAR is neither declared nor bound 但实际上并没有找到解决方案,除了 OP 意识到他犯了一个“打字错误”。在 REPL 中,我可以使用 setf 函数,它工作正常。我也在使用带有 emacs 的 LispBox。如有任何建议,我将不胜感激!

(defun it-fact(num)
  (setf result 1)
  (dotimes (i num)
    (setf result (* result (+ i 1)))
  )
)

IT-FACT 中的警告: RESULT 既没有声明也没有约束, 它将被视为已声明为 SPECIAL。

【问题讨论】:

标签: lisp scope lexical-scope


【解决方案1】:

Lisp 风格存在一些问题或不太好的地方:

(defun it-fact(num)                      ; style: use a space before (
  (setf result 1)                        ; bad: variable RESULT is not introduced
  (dotimes (i num)
    (setf result (* result (+ i 1)))     ; bad: extra addition in each iteration
  )                                      ; style: parentheses on a single line
)                                        ; bad: no useful return value

一个可能的版本:

(defun it-fact (num)
  (let ((result 1))                      ; local variable introduced with LET
    (loop for i from 1 upto num          ; I starts with 1, no extra addition
      do (setf result (* result i)))
    result))                             ; result gets returned from the LET

【讨论】:

  • 感谢您的建议!是的,我意识到 dotimes 从 0 开始,如果我没有在乘法中增加它,它总是会返回 0...你的循环看起来更容易阅读。我想我在每一行都加了括号,因为我仍然习惯于 c++/java 的大括号,但我会尝试采用你的 lisp 实践。哎呀,是的,我忽略了回报,感谢您指出这些事情!
【解决方案2】:

在 Lisp 中,局部变量必须用 LET 或其他创建局部变量的形式显式声明。 这不同于例如在 Python 或 JavaScript 中,对变量的赋值会在当前词法范围内创建变量。

你的例子可以改写成这样:

(defun it-fact(num)
  (let ((result 1))
    (dotimes (i num)
      (setf result (* result (+ i 1))))))

题外话:将右括号放在单独的行上是没有意义的。

【讨论】:

    【解决方案3】:

    在开始使用之前,您需要绑定变量“result”——例如使用“let”:

    (defun it-fact(num)
      (let ((result 1))
        (dotimes (i num)
          (setf result (* result (+ i 1))))))
    

    有关更多详细信息,您可能需要阅读this ...

    【讨论】:

    • 哦,我明白了。我之前也尝试过'let',但我使用它就像它是setf一样,并且我没有在let的括号内包含dotimes循环。我想这与范围或其他东西有关。感谢大家的帮助!
    • 由于我主要是一名 java 程序员,你可以很容易地看出我为什么要去掉括号(把它们看作只不过是括号)。由于这里提供的示例,我已经习惯于将右括号放在一行中,所以这“真的”没什么大不了的。谢谢你:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 2011-10-10
    • 2021-12-11
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多