关于elisp let 函数局部变量的问题

(defun cicle-area (radix)
  (let ((pi 3.1415926) area))
  (setq area (* pi radix radix))
  (message "The area is %f" area))

(cicle-area 3)
输出结果了28.274334

请注意let的括号在第一行就终止了let的作用域吧

请问为什么message 能够认得到area 并且值是正确的?

不是,一直到 let 结束。C-h f let (describe-function) 或 C-h S let (info-lookup-symbol) 里有说明:

 -- Special Form: let (bindings...) forms...
     This special form sets up local bindings for a certain set of
     variables, as specified by BINDINGS, and then evaluates all of the
     FORMS in textual order.  Its return value is the value of the last
     form in FORMS.

没信息表明第一个 form 就结束,而且假设是这样的话,可能就只会允许写一个 form。

你好像没看仔细,let结束就是主楼说的“第一行”,例子里let的forms...部分是空无一物,非常奇怪。

另外bindings部分的第二个是一个area,不是通常的(key "val"),我也很不明白。

(let ((x 1)
      foo)
    body...)

;;; 等于

(let ((x 1)
      (foo nil))
    body...)
1 个赞
(let ((pi 3.1415926) area))
  (setq area (* pi radix radix))
  (message "The area is %f" area)

;; 等价于

(let ((pi 3.1415926) area))
  (progn (setq area (* pi radix radix))
         (message "The area is %f" area))

缩进不对,误导了大家。用 Emacs 缩进一下就好了,let 完全没用,删掉都行。

至于为什么正确,首先 pi 本身就绑定了值,然后你用 setq 创建了一个新的全局变量 area。。你把代码里的 pi 替换成比如 my-pi,代码就没法跑了。

1 个赞
(defun circle-area (rad)
  (let ((area (* pi rad rad)))
    (message "The area is %f" area)
    area))


;; 或者更规范一点

(defun circle-area (rad)
  (interactive)
  (let ((area (* pi rad rad)))
    (if (called-interactively-p 'any)
        (message "The area is %f" area))
    area))
1 个赞

原来是这样 :sweat:

请问正确的缩进格式是怎么样的? 另外有没有什么命令可以自己对整个语句进行缩进格式化

Emacs 会自动处理格式,用 M-\ 键。