CLISP 中忽略了 DYNAMIC-EXTENT?
DYNAMIC-EXTENT ignored in CLISP?
我读到 here "it is permissible for an implementation to ignore" Common Lisp 中的动态范围声明,我想知道它是否在 CLISP 实现中实际上被忽略了。
我已尝试使用以下代码进行测试:
(let ((b (cons 1 2)))
(declare (dynamic-extent b))
(list b))
哪个returns:
((1 . 2))
我的猜测是它被忽略了,但我想确定一下。
此外,如果它被忽略,我有没有办法显式地将内存分配给堆栈而不是堆?
是的,CLISP 会忽略 dynamic-extent
声明。
请参阅 CLISP Implementation Notes, which do not mention it explicitly yet (the beta version。
如果你想控制内存管理(例如,你喜欢调试段错误和内存泄漏),你应该使用 C。
PS。尊重 dynamic-extent
声明的实现可能会在您的代码中出现段错误。
> 有没有办法明确地将内存分配给堆栈而不是堆?
不,您可以感谢它,因为它消除了程序中的一整类错误:不会有 "dangling pointers" 导致程序崩溃的已死对象。
此外,使用 CLISP 或类似的实现,您不需要堆栈分配的内存,因为:
- 垃圾收集器快速消除短寿命对象,CLISP 的垃圾收集器通常消耗不到 CPU 时间的 10%。
- CLISP 的垃圾收集器是分代的,这意味着收集短期对象特别快。一旦收集了一个短期对象,下一个短期对象将被分配到同一个小内存区域 - 所以你有一个类似于堆栈的速度改进(通过使用局部性)。
最后,坚持对象的堆栈分配使您无法自由选择适合您的问题的编程风格。 Lisp 支持多种编程风格:函数式、过程式、面向对象、基于模式、逻辑、关系、规则、面向目标等等。通过请求堆栈分配,您可以限制自己使用函数式和过程式编程风格;这真的不会让你前进。
这真是个好问题! (讨好自己,因为我的业力太低了!)
正如其他人提到的,CLISP 会忽略 declare
dynamic-extent
。然而,其他实现确实遵守它,并且有充分的理由。引用 SBCL:
SBCL has fairly extensive support for performing allocation on the
stack when a variable is declared dynamic-extent
. The
dynamic-extent
declarations are not verified, but are simply
trusted as long as sb-ext:*stack-allocate-dynamic-extent*
is
true.
此外,请记住,CL 声明是由 程序员 lisp 系统做出的承诺。一般而言,无论是在程序员信守诺言还是违背诺言时,声明都没有定义可观察的行为。
总是有帮助和愉快的 SBCL 文档接着说:
If dynamic extent constraints specified in the Common Lisp standard
are violated, the best that can happen is for the program to have
garbage in variables and return values; more commonly, the system will
crash.
In particular, it is important to realize that dynamic extend is
contagious:
(let* ((a (list 1 2 3))
(b (cons a a)))
(declare (dynamic-extent b))
;; Unless A is accessed elsewhere as well, SBCL will consider
;; it to be otherwise inaccessible -- it can only be accessed
;; through B, after all -- and stack allocate it as well.
;;
;; Hence returning (CAR B) here is unsafe.
...)
要点是:通常在 lisp 声明中不会导致符合程序的 'meaning' 发生变化。如果您的程序与您声明的意图背道而驰,则所有赌注都会被取消。声明的 'effect' 是什么,即编译器 如何 优化生成的代码(以及它是否优化它)因实现而异,甚至因版本而异.
我读到 here "it is permissible for an implementation to ignore" Common Lisp 中的动态范围声明,我想知道它是否在 CLISP 实现中实际上被忽略了。
我已尝试使用以下代码进行测试:
(let ((b (cons 1 2)))
(declare (dynamic-extent b))
(list b))
哪个returns:
((1 . 2))
我的猜测是它被忽略了,但我想确定一下。
此外,如果它被忽略,我有没有办法显式地将内存分配给堆栈而不是堆?
是的,CLISP 会忽略 dynamic-extent
声明。
请参阅 CLISP Implementation Notes, which do not mention it explicitly yet (the beta version。
如果你想控制内存管理(例如,你喜欢调试段错误和内存泄漏),你应该使用 C。
PS。尊重 dynamic-extent
声明的实现可能会在您的代码中出现段错误。
> 有没有办法明确地将内存分配给堆栈而不是堆?
不,您可以感谢它,因为它消除了程序中的一整类错误:不会有 "dangling pointers" 导致程序崩溃的已死对象。
此外,使用 CLISP 或类似的实现,您不需要堆栈分配的内存,因为:
- 垃圾收集器快速消除短寿命对象,CLISP 的垃圾收集器通常消耗不到 CPU 时间的 10%。
- CLISP 的垃圾收集器是分代的,这意味着收集短期对象特别快。一旦收集了一个短期对象,下一个短期对象将被分配到同一个小内存区域 - 所以你有一个类似于堆栈的速度改进(通过使用局部性)。
最后,坚持对象的堆栈分配使您无法自由选择适合您的问题的编程风格。 Lisp 支持多种编程风格:函数式、过程式、面向对象、基于模式、逻辑、关系、规则、面向目标等等。通过请求堆栈分配,您可以限制自己使用函数式和过程式编程风格;这真的不会让你前进。
这真是个好问题! (讨好自己,因为我的业力太低了!)
正如其他人提到的,CLISP 会忽略 declare
dynamic-extent
。然而,其他实现确实遵守它,并且有充分的理由。引用 SBCL:
SBCL has fairly extensive support for performing allocation on the stack when a variable is declared
dynamic-extent
. Thedynamic-extent
declarations are not verified, but are simply trusted as long assb-ext:*stack-allocate-dynamic-extent*
is true.
此外,请记住,CL 声明是由 程序员 lisp 系统做出的承诺。一般而言,无论是在程序员信守诺言还是违背诺言时,声明都没有定义可观察的行为。
总是有帮助和愉快的 SBCL 文档接着说:
If dynamic extent constraints specified in the Common Lisp standard are violated, the best that can happen is for the program to have garbage in variables and return values; more commonly, the system will crash.
In particular, it is important to realize that dynamic extend is contagious:
(let* ((a (list 1 2 3))
(b (cons a a)))
(declare (dynamic-extent b))
;; Unless A is accessed elsewhere as well, SBCL will consider
;; it to be otherwise inaccessible -- it can only be accessed
;; through B, after all -- and stack allocate it as well.
;;
;; Hence returning (CAR B) here is unsafe.
...)
要点是:通常在 lisp 声明中不会导致符合程序的 'meaning' 发生变化。如果您的程序与您声明的意图背道而驰,则所有赌注都会被取消。声明的 'effect' 是什么,即编译器 如何 优化生成的代码(以及它是否优化它)因实现而异,甚至因版本而异.