更改hunchentoot的当前包

时间:2013-03-22 02:06:45

标签: package common-lisp

我已经使用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做我想做的事,有没有理由为什么我的'凌乱的黑客'仍然是更好的事情?

3 个答案:

答案 0 :(得分:3)

这不是一个Hunchentoot特定问题,但一般与Common Lisp包有关。

您所看到的是,在您的代码中,*PACKAGE*特殊变量未绑定到您自己的包中。 IN-PACKAGE仅在编译和阅读时更改*PACKAGE*。在运行时调用包中的函数时,*PACKAGE*不会重新绑定,需要明确绑定。

当您使用INTERNFIND-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)))