【问题标题】:Why does lexical variable retains value? [duplicate]为什么词法变量保留值? [复制]
【发布时间】:2019-07-07 19:35:14
【问题描述】:

我看不懂下面的代码:

(defun my-test ()
  (let ((temp '(())))
    (format t "temp: ~a~%" temp)
    ((lambda ()
       (push 5 (first temp))))))

;; Execute this call twice in a row.
(my-test)

输出:

temp: (NIL)
temp: ((5))

temp如何保存值?我知道有以下警告,但我不明白这种行为背后的逻辑。

; in: DEFUN MY-TEST
;     (PUSH 5 (FIRST TEMP))
; --> LET* 
; ==>
;   (SB-KERNEL:%RPLACA #:TEMP0 (CONS 5 (FIRST #:TEMP0)))
; 
; caught WARNING:
;   Destructive function SB-KERNEL:%RPLACA called on constant data: (NIL)
;   See also:
;     The ANSI Standard, Special Operator QUOTE
;     The ANSI Standard, Section 3.2.2.3
; 
; compilation unit finished
;   caught 1 WARNING condition

以下代码输出相同的结果:

(flet ((my-fct ()
     (let ((temp '(())))
       (format t "temp: ~a~%" temp)
       ((lambda ()
          (push 5 (first temp)))))))
  (my-fct)
  (my-fct))

(let ((fct (lambda ()
         (let ((temp '(())))
           (format t "temp: ~a~%" temp)
           ((lambda ()
          (push 5 (first temp))))))))
  (funcall fct)
  (funcall fct))

但这一个有效:

;; Execute this call twice in a row.
((lambda ()
   (let ((temp '(())))
     (format t "temp: ~a~%" temp)
     ((lambda ()
    (push 5 (first temp)))))))

这个也可以:

(defun my-test ()
  (let ((temp (list ())))
    (format t "temp: ~a~%" temp)
    ((lambda ()
       (push 5 (first temp))))))

(my-test)

还有这个:

(defun my-test ()
  (let ((temp (list (list))))
    (format t "temp: ~a~%" temp)
    ((lambda ()
       (push 5 (first temp))))))

(my-test)

但不是这个:

(defun my-test ()
  (let ((temp `(,(list))))
    (format t "temp: ~a~%" temp)
    ((lambda ()
       (push 5 (first temp))))))

(my-test)

  • 为什么它对某些代码有效,而对另一些代码无效?
  • 如何在多次调用中保留词法值?

【问题讨论】:

  • 该死的。我做了一个回答,寻找像`(,(list)) 这样的特殊情况,我觉得这很有趣。我认为他正在使用 SBCL,它实际上不断地将 (list) 折叠到 (),这使得整个事情 '(())。此外,第一个 OP 说,如果您将其保存为文件并加载已编译的版本,则 SBCL 中不起作用。然后文件中所有位置的'(()) 被一个实例替换,并改变第一个实例。
  • @Sylwester :我确实使用了 SBCL,但没有编译文件。 Common Lisp 太酷了。 :D

标签: common-lisp


【解决方案1】:

Common Lisp 规范没有指定当您尝试改变常量数据时会发生什么。常量数据为:

  1. quote 运算符生成的数据
  2. 计算结果为自身并且是源代码一部分的任何对象

这样做的目的是允许实现使用只读内存(不需要被 gc 扫描)来存储常量,并为相等的常量重用存储空间。

所以代码:

(defun foo ()
  ... '(()) ...)

可以转换为:

(defconstant +foo1+ '(()))
(defun foo ()
  ... +foo1+ ...)

不偏离标准的文字或精神。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-28
    • 2013-01-14
    • 2020-06-15
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-19
    相关资源
    最近更新 更多