以下CL代码片段无法正常运行,因为CCL运行SLIME。如果我
首先使用C-c C-k
编译并加载文件,然后运行
(rdirichlet #(1.0 2.0 3.0) 1.0)
在SLIME / CCL REPL中,我收到错误
value 1.0 is not of the expected type DOUBLE-FLOAT.
[Condition of type TYPE-ERROR]
适用于SBCL。我希望(setf *read-default-float-format* 'double-float))
允许我使用1.0
之类的值。如果我使用REPL中的LOAD
将此文件加载到CCL中,则可以正常工作。我错过了什么?
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :asdf) (require :cl-rmath) (setf *read-default-float-format* 'double-float))
(defun rdirichlet (alpha rownum)
;;(declare (fixnum rownum))
(let* ((alphalen (length alpha))
(dirichlet (make-array alphalen :element-type '(double-float 0.0 *) :adjustable nil :fill-pointer nil :displaced-to nil)))
(dotimes (i alphalen)
(setf (elt dirichlet i) (cl-rmath::rgamma (elt alpha i) rownum)))
;; Divide dirichlet vector by its sum
(map 'vector #'(lambda (x) (/ x (reduce #'+ dirichlet))) dirichlet)))
更新:我忘了提及我的平台和版本。我正在使用Debian挤压x86。 SLIME的版本来自Debian unstable,1:20120525-2
。
CCL是1.8版本。我用http://svn.clozure.com/publicsvn/openmcl/release/1.8/linuxx86/ccl的上游二进制文件和我创建的二进制包尝试了它 - 请参阅Package ccl at mentors.debian.net。结果在每种情况下都是相同的。
这个问题似乎很可能是特定于SLIME的。如果人们可以评论他们是否看到这种行为会很有帮助。也,
如果在基本命令行模式下运行CCL,SLIME中等效于C-c C-k
的是什么? (LOAD filename)
还是其他什么?或者,问一个稍微不同的问题,CCL函数是C-c C-k
调用的吗?
我注意到在以下代码中调用C-c C-k
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :asdf) (require :cl-rmath) (setf *read-default-float-format* 'double-float))
(print *read-default-float-format*)
生成DOUBLE-FLOAT
,但即使后面的REPL *read-default-float-format*
提供了SINGLE-FLOAT
。
更新2:正如Rainer所说,看起来编译发生在一个单独的线程中。
中的all-processes
函数
使用C-c C-k从缓冲区打印all-processes
(#<PROCESS worker(188) [Active] #x18BF99CE> #<PROCESS repl-thread(12) [Semaphore timed wait] #x187A186E> #<PROCESS auto-flush-thread(11) [Sleep] #x187A1C9E> #<PROCESS swank-indentation-cache-thread(6) [Semaphore timed wait] #x186C128E> #<PROCESS reader-thread(5) [Active] #x186C164E> #<PROCESS control-thread(4) [Semaphore timed wait] #x186BE3BE> #<PROCESS Swank Sentinel(2) [Semaphore timed wait] #x186BD0D6> #<TTY-LISTENER listener(1) [Active] #x183577B6> #<PROCESS Initial(0) [Sleep] #x1805FCCE>)
CL-USER> (all-processes)
并在REPL中给出
(#<PROCESS repl-thread(12) [Active] #x187A186E> #<PROCESS auto-flush-thread(11) [Sleep] #x187A1C9E> #<PROCESS swank-indentation-cache-thread(6) [Semaphore timed wait] #x186C128E> #<PROCESS reader-thread(5) [Active] #x186C164E> #<PROCESS control-thread(4) [Semaphore timed wait] #x186BE3BE> #<PROCESS Swank Sentinel(2) [Semaphore timed wait] #x186BD0D6> #<TTY-LISTENER listener(1) [Active] #x183577B6> #<PROCESS Initial(0) [Sleep] #x1805FCCE>)
所以似乎#<PROCESS worker(188) [Active] #x18BF99CE>
是正在进行编译的线程。当然,仍然存在这样的问题:为什么这些变量是线程的局部变量,也是为什么SBCL的行为方式不同。
答案 0 :(得分:3)
我可以看到CCL和一些较旧的(我使用的)SLIME。没有尝试过更新的SLIME。
SBCL或LispWorks不会发生这种情况。
*read-default-float-format*
是Common Lisp的I / O变量之一。像WITH-STANDARD-IO-SYNTAX
之类的东西将它们绑定到标准值,并在退出时恢复以前的值。所以我怀疑CCL的SLIME代码实际上有这样的绑定。这可以通过设置其他I / O变量来确认,例如*read-base*
- 它们也是绑定的。
CCL,Emacs和SLIME有一些代码层,这使得调试它有点复杂。
在Emacs端使用SLIME / ELISP函数SLIME-COMPILE-AND-LOAD-FILE
。
在SWANK端,调用Common Lisp函数swank:compile-file-for-emacs
。
稍后调用SWANK:LOAD-FILE
。
我看不到I / O变量的绑定位置 - 可能是在CCL网络代码中?
这似乎是答案:
如果CCL具有线程局部I / O变量,则编译在另一个线程中发生,并且不会更改REPL线程中的I / O绑定,也不会更改任何其他线程中的I / O绑定。
这是各种CL实现之间的差异。由于CL标准没有指定线程或进程,因此如果特殊绑定是全局的或默认情况下具有线程局部绑定,也不会指定它...
如果你考虑一下,保护线程的I / O变量免受来自其他线程的更改是有意义的......
因此,处理它的正确方法应该是在每个线程中确保正确的I / O变量值有效。
让我扩展一下为什么事情就像它们一样。
通常,Common Lisp实现可以运行多个线程。某些实现还允许并发线程在不同的核心上同时运行。这些线程可以做很多不同的事情:一个可以运行REPL,另一个可以应答HTTP请求,一个可以从磁盘加载数据,另一个可以读取电子邮件的内容。在这种情况下,Lisp在一个Lisp系统中运行几个不同的任务。
Lisp有几个变量决定了I / O操作的行为。例如,读取时浮动的格式或读取时的基本整数数。这封信由` read-base 完成。
现在假设上面的磁盘读取线程已将其*read-base*
设置为16用于某种目的。现在你将另一个线程中的全局更改为8然后突然所有其他线程都有8个。结果:磁盘读取线程将突然看到*read-base*
8而不是16并且工作方式不同。
因此以某种方式防止这种情况是有道理的。最简单的是,在每个线程中,正在运行的代码都有自己的I / O值绑定,然后更改*read-base*
将不会对其他线程产生影响。这些绑定通常由LET
或函数调用引入。通常,代码负责绑定变量。
另一种防止它的方法是给每个线程一些初始绑定,例如应包括I / O绑定。 CCL这样做。例如,LispWorks也是这样做的。但不适用于I / O变量。
现在,每个Lisp都可能为您提供一种不可移植的方式来更改线程本地顶部绑定(CCL也具有此功能 - 例如(setf ccl:symbol-value-in-process)
)。但这并不意味着它可能会改变REPL中的约束力。由于REPL本身是一段Lisp代码,在一个线程中运行,它可能已经设置了自己的绑定。
在CCL中,您还可以设置全局静态绑定:(CCL::%SET-SYM-GLOBAL-VALUE sym value)
。但是如果你使用这样的功能,你可能做错了什么或者你有充分的理由。
CCL的一些背景知识:http://clozure.com/pipermail/openmcl-devel/2011-June/012882.html
<强>洛雷强>