0

根据 Xach 的说明,我已经使用 quickproject 建立了一个 hunchentoot 项目。In-package 在文件顶部运行,hunchentoot 在文件后面启动。REPL 也切换到我的包中,但很明显 hunchentoot 没有在我的包中运行。这会导致 REPL 和浏览器中的测试之间存在一些差异。例如,有一个函数在 alist 中查找一些东西,但是 hunchentoot 从中获取 NIL,因为它使用了另一个包中的符号。

我从这个相关问题的答案中知道,我可以将每一段用于实习符号的代码包装成类似的东西

(let ((*package* (find-package :package-name)))
  ...)

这将*package*在所附代码的持续时间内将 var 设置为正确的包。

把它放在每一个需要它的功能中,我感觉就像一个凌乱的黑客。

直觉说我应该可以像这样开始 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 做我想做的事,我的“乱七八糟的黑客”仍然是更好的做法吗?

4

3 回答 3

3

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

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

当您使用INTERNorFIND-SYMBOL时,通常最好将包指定为参数。或者,您可以绑定*PACKAGE*自己。

试试看LOAD这个文件:

(defpackage :foo
  (:use :cl))

(in-package :foo)

(defun test ()
  (print *package*))

(in-package :cl-user)

(foo::test)
于 2013-03-22T07:05:05.243 回答
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*作为包相关操作的默认包。使用该机制时需要设置或绑定该变量。

于 2013-03-22T08:25:41.763 回答
1

当 Hunchentoot 在多线程中运行时,它的接受器和处理程序在使用bordeaux-threads非 Lispwork CL 实现的子线程中处理。你问的这种情况的原因是当前子线程的包变成了COMMON-LISP-USER.

为了得到你想要的结果,你可以使子线程的当前包与调用线程的包相同,并实现START-THREAD对应于ONE-THREAD-PER-CONNECTION-TASKMASTERtaskmaster 的通用函数。

请注意,您使用的是具有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)))
于 2013-08-15T00:34:00.027 回答