Common lisp setq与未声明的自由变量(公共lisp)

Common lisp setq与未声明的自由变量(公共lisp),common-lisp,Common Lisp,我是个口齿不清的人,所以请温柔一点 我很难理解CL关于[un-]声明自由变量的想法。我认为: (defun test () (setq foo 17) ) 将定义一个声明变量foo并将其设置为17的函数。然而,我得到的却是 ;Compiler warnings : ; In TEST: Undeclared free variable FOO 我的实际案例要大一点;我的代码(片段)如下所示: (defun p8 () ;;; [some other stuff, snip]

我是个口齿不清的人,所以请温柔一点

我很难理解CL关于[un-]声明自由变量的想法。我认为:

(defun test ()
    (setq foo 17)
)
将定义一个声明变量foo并将其设置为17的函数。然而,我得到的却是

;Compiler warnings :
;  In TEST: Undeclared free variable FOO
我的实际案例要大一点;我的代码(片段)如下所示:

(defun p8 ()
    ;;; [some other stuff, snip]

    (loop for x from 0 to (- (length str) str-len) do
        (setq last (+ x str-len))           ; get the last char of substring
        (setq subs (subseq str x last))     ; get the substring
        (setq prod (prod-string subs))      ; get the product of that substring
        (if (> prod max)                    ; if it's bigger than current max, save it
            (setq max prod)
            (setq max-str subs)
        )
    )

;;; [More stuff, snip]
)
(loop for x from 0 to (- (length str) str-len) do
    (let* ((last (+ x str-len))         ; get the last char of substring
           (subs (subseq str x last))   ; get the substring
           (prod (prod-string subs)))   ; get the product of that substring
      (if (> prod max)                    ; if it's bigger than current max, save it
          (setq max prod)
          (setq max-str subs))))
这给了我:

;Compiler warnings for "/path/to/Lisp/projectEuler/p6-10.lisp":
;   In P8: Undeclared free variable LAST (2 references)
;Compiler warnings for "/Volumes/TwoBig/AllYourBits-Olie/WasOnDownBelowTheOcean/zIncoming/Lisp/projectEuler/p6-10.lisp" :
;   In P8: Undeclared free variable PROD (3 references)
;Compiler warnings for "/Volumes/TwoBig/AllYourBits-Olie/WasOnDownBelowTheOcean/zIncoming/Lisp/projectEuler/p6-10.lisp" :
;   In P8: Undeclared free variable SUBS (3 references)
;Compiler warnings for "/Volumes/TwoBig/AllYourBits-Olie/WasOnDownBelowTheOcean/zIncoming/Lisp/projectEuler/p6-10.lisp" :
;   In P8: Undeclared free variable =
是的,是的,我意识到我使用了太多的中间变量,但我试图在我太喜欢将所有内容压缩到最小类型的字符之前了解发生了什么,这在CL世界中似乎很流行

所以,不管怎样。。。有人能解释一下吗

  • Lisp在什么条件下“声明”变量
  • 所述变量的范围是否不是围绕
    setq
    语句的封闭
    (…)
    ?!(也就是说,我希望var对
    (…(setq…)
    setq之外的parens 1级别的所有内容都有效,没有
  • 我是否错误地解释了未声明的自由变量消息
  • 你想给我的任何其他提示都会帮助我更好地了解这里发生了什么
注意:我非常精通C、Java、Javascript、Obj-C和相关的过程语言。我知道函数式编程是不同的。现在,我只是在与语法搏斗

谢谢


另外,如果这很重要,
defun p8
在一个文本文件(TextMate)中,我正在
Clozure CL
上运行它。不过,希望这些都不重要!

在Lisp变量声明中可以通过多种方式执行。最值得注意的是:

  • 使用
    defparameter
    defvar
  • 使用
    let
    let*
    多值绑定
    解构绑定
    和其他绑定形式声明局部变量
  • 作为函数参数
您也可以在许多地方了解它们的范围,例如在

setq
/
setf
不是变量声明运算符,而是变量修改运算符,正如它们的名称所暗示的那样


PS.在交互模式下,如果您试图设置一个未声明的变量,一些实现会使用DWIM方法,并在后台将变量声明为特殊变量,但这纯粹是为了方便。

在lisp中,变量可以使用
defparameter
defvar
声明

(defparameter var1 5)
(defvar var2 42)
这将导致全局(动态)变量

defvar
defparameter
之间的区别在于
defvar
不会重新初始化已经存在的变量

引入局部(词汇)变量,例如使用
let
let*
(按顺序初始化变量)

未声明的自由变量表示您使用了(此处为
setq
-ed)一个未在其使用的上下文中绑定的变量。然后可以为您声明该变量,但可能是一个全局变量(动态变量)这样做的结果是,如果在多个函数中使用名称相同的未声明变量,那么在所有函数中都将引用相同的变量

您的代码可以这样编写:

(defun p8 ()
    ;;; [some other stuff, snip]

    (loop for x from 0 to (- (length str) str-len) do
        (setq last (+ x str-len))           ; get the last char of substring
        (setq subs (subseq str x last))     ; get the substring
        (setq prod (prod-string subs))      ; get the product of that substring
        (if (> prod max)                    ; if it's bigger than current max, save it
            (setq max prod)
            (setq max-str subs)
        )
    )

;;; [More stuff, snip]
)
(loop for x from 0 to (- (length str) str-len) do
    (let* ((last (+ x str-len))         ; get the last char of substring
           (subs (subseq str x last))   ; get the substring
           (prod (prod-string subs)))   ; get the product of that substring
      (if (> prod max)                    ; if it's bigger than current max, save it
          (setq max prod)
          (setq max-str subs))))
使用循环的变量绑定属性,它也可以写成

(loop for x from 0 to (- (length str) str-len)
      for last = (+ x str-len)
      for subs = (subseq str x last)
      for prod = (prod-string subs)
      when (> prod max) do
          (setq max prod)
          (setq max-str subs))
Common Lisp HyperSpec(基本上是HTML格式的Common Lisp标准)表示:

为变量赋值

所以
SETQ
只给变量赋值,而不声明它们

变量定义通过
DEFVAR
DEFPARAMETER

(defparameter *this-is-a-global-dynamic-variable* 'yep)
变量定义是通过
DEFUN
LET
LET*
LOOP
和许多其他方法在本地完成的

(defun foo (v1 v2)
  ...)

(let ((v1 10)
      (v2 20))
  ...)

(loop for v1 in '(10 30 10 20)
      do ...)
这是基本的Lisp,阅读介绍会很有用。我建议:

以上书免费下载

此外,上述通用Lisp Hyperspec为您提供了通用Lisp的定义,并详细描述了各种工具(DEFUN、LOOP、DEFPARAMETER等)