它超出了 CL 标准的范围。一些 CL 实现可能会做这些奇怪的事情,但其他可能不会。我记得我在学习 CL 时发现了类似的东西。我的版本是这样的:
(defun counter1 (&optional (x '(-1)))
(rplaca x (+ (car x) 1))
(car x))
(counter1) ; ==> 0
(counter1) ; ==> 1
(counter1) ; ==> 2
这里和您的代码中发生的事情是可选的x
和state
是常量。它只存在其中之一,如果您更改它,您将永久更改它。在我的例子中;如果默认值是(cons -1 ())
,如果我不提供,它将始终返回 0 x
。为什么你有两个嵌套的 let 是(cadr state)
因为rplacd
. 我敦促您将其删除并替换ans
为(cadr state)
以查看差异。
如果您想要标准中的相同功能,以下是示例代码的外观:
(defun element-generator ()
(let ((state (list () 'list 'of 'elements 'to 'be 'generated))); Make closure
#'(lambda () ;create function
(let ((ans (cadr state))) ;pick off the second element
(rplacd state (cddr state)) ;mutate the list in the closure
ans)))) ;return element
(setf (symbol-function 'gen1) (element-generator))
(setf (symbol-function 'gen2) (element-generator))
(gen1) ; ==> LIST
(gen1) ; ==> OF
(gen1) ; ==> ELEMENTS
(gen2) ; ==> LIST
(gen2) ; ==> OF
(gen1) ; ==> TO
在这里,每个元素生成器实例都会获得一个新的闭包,当您调用它返回的函数时,您将从该闭包中获取元素。查看返回的两个函数如何拥有自己的列表版本。由于我们没有破解标准,我们不妨将其重写为 mutate state 而不是列表:
(defun element-generator ()
(let ((state (list 'list 'of 'elements 'to 'be 'generated))) ; create closure
#'(lambda () ;create function
(let ((ans (car state))) ;pick off the first element
(setf state (cdr state)) ;mutate state to point to next element
ans)))) ;return first element
它将表现相同。