我已经使用quickproject设置了一个hunchentoot项目,每个Xach的instructions.包内运行在文件的顶部,hunchentoot稍后在文件中启动。 REPL也切换到我的包,但很明显hunchentoot没有在我的包中运行。这导致REPL和浏览器中的测试之间存在一些差异。例如,有一个函数在alist中查找一些东西,但是hunchentoot从中获取NIL,因为它使用的是另一个包中的符号。
我从this related question的答案中知道,我可以将每一段内容符号的代码包装成
(let ((*package* (find-package :package-name)))
...)
将在封闭代码的持续时间内将*package*
var设置为正确的包。
将它放在需要它的每个功能中,对我来说就像一个混乱的黑客。
Intuition说我应该能够像这样开始hunchentoot:
(let ((*package* (find-package :package-name)))
(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 4242)))
这样它就可以将*package*
的整个运行设置为我喜欢的值,从而确保来自网络服务器的调用在我的包中完成的任何实习。它不起作用。 Hunchentoot最终会在cl-user下实现内容,可能是由于使用了像上面链接中的WITH-STANDARD-IO-SYNTAX这样的宏。
即使我能说服hunchentoot做我想做的事,有没有理由为什么我的'凌乱的黑客'仍然是更好的事情?
答案 0 :(得分:3)
这不是一个Hunchentoot特定问题,但一般与Common Lisp包有关。
您所看到的是,在您的代码中,*PACKAGE*
特殊变量未绑定到您自己的包中。 IN-PACKAGE
仅在编译和阅读时更改*PACKAGE*
。在运行时调用包中的函数时,*PACKAGE*
不会重新绑定,需要明确绑定。
当您使用INTERN
或FIND-SYMBOL
时,通常最好将包指定为参数。或者,您可以自己绑定*PACKAGE*
。
尝试LOAD
此文件以查看:
(defpackage :foo
(:use :cl))
(in-package :foo)
(defun test ()
(print *package*))
(in-package :cl-user)
(foo::test)
答案 1 :(得分:3)
Common Lisp代码不会在包中“运行”。
有一些操作使用默认包。就像从文本流中读取符号一样:
CL-USER 1 > *package*
#<The COMMON-LISP-USER package, 56/64 internal, 0/4 external>
CL-USER 2 > (read-from-string "FOO")
FOO
3
CL-USER 3 > (describe (read-from-string "FOO"))
FOO is a SYMBOL
NAME "FOO"
VALUE #<unbound value>
FUNCTION #<unbound function>
PLIST NIL
PACKAGE #<The COMMON-LISP-USER package, 57/64 internal, 0/4 external>
或者喜欢找一个符号:
(find-symbol "FOO")
这些操作取决于变量cl:*package*
的值。
为确保这些操作(阅读符号,查找符号,实习符号......)符合您的预期,您可能需要:
将*package*
变量设置或绑定到您想要的包
显式将包传递给操作。您可以致电(find-symbol "FOO")
并将*package*
设置为某个套餐。但是你也可以通过传递相应的包作为参数来调用(find-symbol "FOO" my-package)
。
摘要:Common Lisp代码不“在包中运行”,但它使用变量*package*
作为与包相关的操作的默认包。使用此机制时,需要设置或绑定此变量。
答案 2 :(得分:1)
当Hunchentoot在多线程中运行时,其接受器和处理程序在非Lispwork CL实现的bordeaux-threads
子线程中处理。你问的情况的原因是子线程的当前包变为COMMON-LISP-USER
。
要获得所需的结果,可以使子线程的当前包与调用线程相同,并实现与START-THREAD
taskmaster相对应的ONE-THREAD-PER-CONNECTION-TASKMASTER
泛型函数。
请注意,您使用的是具有START-THREAD
通用功能的最新Hunchentoot,我使用的是版本1.2.19。
(in-package :hunchentoot)
(defmethod start-thread ((taskmaster one-thread-per-connection-taskmaster) thunk &key name)
(let* (;; calling thread's current package
(package-name (package-name *package*))
;; initial special bindings passed to bordeaux threads
(initial-bindings `((*package* . (find-package ,package-name)))))
;; making child thread passing initial special bindings
(bt:make-thread thunk :name name :initial-bindings initial-bindings)))