CLISP中是否忽略了动态范围?

CLISP中是否忽略了动态范围?,lisp,common-lisp,heap-memory,clisp,stack-memory,Lisp,Common Lisp,Heap Memory,Clisp,Stack Memory,我在CommonLisp中读到“允许实现忽略”动态范围声明,我想知道它是否在CLISP实现中被忽略 我已尝试使用以下代码进行测试: (let ((b (cons 1 2))) (declare (dynamic-extent b)) (list b)) 返回: ((1 . 2)) 我猜它被忽略了,但我想确定一下 另外,如果忽略它,是否有一种方法可以显式地将内存分配给堆栈而不是堆?是的,CLISP忽略动态范围声明。 看,这还没有明确提到它(是的) 如果您想要控制内存管理(例如,您喜欢调

我在CommonLisp中读到“允许实现忽略”动态范围声明,我想知道它是否在CLISP实现中被忽略

我已尝试使用以下代码进行测试:

(let ((b (cons 1 2))) 
 (declare (dynamic-extent b)) 
 (list b))
返回:

((1 . 2))
我猜它被忽略了,但我想确定一下


另外,如果忽略它,是否有一种方法可以显式地将内存分配给堆栈而不是堆?

是的,CLISP忽略
动态范围
声明。 看,这还没有明确提到它(是的)

如果您想要控制内存管理(例如,您喜欢调试故障和内存泄漏),您应该使用C

注意:尊重
动态范围声明的实现可能会在您的代码上出错。

>我有没有办法显式地将内存分配给堆栈而不是堆

不,您可以对此表示感谢,因为它消除了程序中的一整类错误:不可能有指向已经死掉的对象的“悬空指针”导致程序崩溃

此外,对于CLISP或类似的实现,您不需要堆栈分配的内存,因为:

  • 垃圾收集器可以快速消除短期对象,而CLISP的垃圾收集器消耗的CPU时间通常不到10%
  • CLISP的垃圾收集器是分代的,这意味着收集短期对象的速度特别快。一旦收集了一个短期对象,下一个短期对象将被分配到同一个小内存区域中——因此,与堆栈相比,您可以获得类似的速度提升(通过使用局部性)

最后,坚持对象的堆栈分配会妨碍您自由选择适合您的问题的编程风格。Lisp支持多种编程风格:函数式、过程式、面向对象、基于模式、逻辑、关系式、规则、面向目标等等。通过请求堆栈分配,您将自己限制为函数式和过程式编程风格;这真的不能让你进步。

这实际上是一个很好的问题!(我的因果报应太低了,你就去讨好我自己吧!)

正如其他人提到的,CLISP忽略
声明
动态范围
。然而,其他实现确实遵守了它,这是有充分理由的。引用SBCL:

SBCL对在服务器上执行分配有相当广泛的支持 声明变量时堆栈
动态范围
。这个
动态范围
声明未经验证,只是简单地 只要
sb ext:*堆栈分配动态范围*
为 对

另外,请记住CL声明是程序员对lisp系统做出的承诺。一般来说,声明没有定义可观察的行为,无论是在程序员信守承诺还是在声明被破坏时

始终有用且令人愉快的SBCL文档接着说:

如果在通用Lisp标准中指定了动态范围约束 如果违反了,最好的办法就是让程序 变量和返回值中的垃圾;更常见的是,该系统将 撞车

特别是,认识到动态扩展是非常重要的 传染性:


外卖是:通常在lisp中,声明不会导致一致性程序的“含义”发生变化。如果您的程序与您声明的意图背道而驰,则所有赌注都将被取消。声明的“效果”是什么,即编译器如何优化生成的代码(以及是否对其进行了优化)因实现而异,甚至因版本而异

谢谢,这很有道理。您知道在CLISP中显式分配内存的方法吗?我知道CLISP有自动内存管理功能,但我想知道是否有办法解决这个问题。@TatsuyaYokota:如果你想控制内存管理,请使用C。虽然我同意它不是经常需要或可取的,但还有其他CL实现支持堆栈分配:如果你绝对确定你需要它的话(不仅仅是无偿地优化一些不需要优化的东西)你可以考虑它们。@ TatsuyaYokota:CFFI将允许你分配内存并与之交互,但当然不是存储LISP对象。静态数组在需要固定数组(潜在非托管)的情况下也是方便的。内存中的点,但它只支持某些数值类型。Clisp不是一个很好的通用LISP实现,请考虑SBCL、CCL(编译为机器代码)或ECL(如果编译为C是必需的)
(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.
   ...)