Common lisp Common Lisp中标签内的未定义函数错误

Common lisp Common Lisp中标签内的未定义函数错误,common-lisp,Common Lisp,我有: 输入REPL(Clozure Common Lisp)时会生成警告: 为什么处理程序变量不可用 这不仅仅是一个警告,运行它可以确认错误: ;Compiler warnings : ; In NEXT-CONNECTION inside SERVE: Undefined function HANDLER ; In SERVE: Unused lexical variable HANDLER 产出: (serve :port 6663 :handler #'do-stuff) 错

我有:

输入REPL(Clozure Common Lisp)时会生成警告:

为什么处理程序变量不可用

这不仅仅是一个警告,运行它可以确认错误:

;Compiler warnings :
;   In NEXT-CONNECTION inside SERVE: Undefined function HANDLER
;   In SERVE: Unused lexical variable HANDLER
产出:

(serve :port 6663 :handler #'do-stuff)
错误:使用参数(#)调用了未定义的函数处理程序

处理程序是否应该可用,因为它在表单上是按词汇关闭的?

我将您的问题归结为:

表明它与
标签
(或带有XXX的
宏)无关

实际的问题是,当Lisp计算列表时,它会查看列表中的第一项,期望它是一个符号,查找符号的function属性,然后调用该函数。(如果您不了解符号的“属性”或“单元”,请告诉我们,我们将对此进行详细介绍。)

如果使用
defun
定义了
handler
,这将起作用,但由于它是
service
中的“局部变量”,因此希望Lisp执行其value属性引用的函数

为此,可以使用Lisp的
funcall
函数。现在最简单的例子是:

(defun serve (handler)
  (handler 'stream))
  • 或者在您的代码
    (funcall处理程序流)

我将您的问题归结为:

表明它与
标签
(或带有XXX的
宏)无关

实际的问题是,当Lisp计算列表时,它会查看列表中的第一项,期望它是一个符号,查找符号的function属性,然后调用该函数。(如果您不了解符号的“属性”或“单元”,请告诉我们,我们将对此进行详细介绍。)

如果使用
defun
定义了
handler
,这将起作用,但由于它是
service
中的“局部变量”,因此希望Lisp执行其value属性引用的函数

为此,可以使用Lisp的
funcall
函数。现在最简单的例子是:

(defun serve (handler)
  (handler 'stream))
  • 或者在您的代码
    (funcall处理程序流)

您可能希望将代码的格式设置得更具可读性。我将使用缩进编辑器执行此操作:

(defun serve (handler)
  (funcall handler 'stream))
请注意,您编写了一个循环,就像在Scheme中一样。 通用口齿不清

(defun serve (&key (port 80) (handler #'IDENTITY))
  (WITH-OPEN-SOCKET (socket
                     :LOCAL-PORT port
                     :LOCAL-HOST "localhost"
                     :CONNECT :PASSIVE
                     :REUSE-ADDRESS t)
     (LABELS ((next-connection ()
                (with-open-stream (stream (ACCEPT-CONNECTION socket :wait t))
                  (funcall handler stream))
                (next-connection)))
       (next-connection))))
只是

(LABELS ((next-connection ()
           (with-open-stream (stream (ACCEPT-CONNECTION socket :wait t))
             (funcall handler stream))
           (next-connection)))
  (next-connection)
优点:

  • 更简单、更少的代码
  • 不需要自递归函数
  • 不需要尾部调用优化来防止堆栈溢出
  • 减少源代码中的嵌套
  • 显式控制流构造明确了目的:这里是一个循环。读者不需要通过试图理解函数调用序列来从代码中推断它
您还可以将连接代码设置为函数,并且仍然使用一个简单的循环:

(loop
 (with-open-stream (stream (ACCEPT-CONNECTION socket :wait t))
   (funcall handler stream)))

您可能希望将代码的格式设置得更具可读性。我将使用缩进编辑器执行此操作:

(defun serve (handler)
  (funcall handler 'stream))
请注意,您编写了一个循环,就像在Scheme中一样。 通用口齿不清

(defun serve (&key (port 80) (handler #'IDENTITY))
  (WITH-OPEN-SOCKET (socket
                     :LOCAL-PORT port
                     :LOCAL-HOST "localhost"
                     :CONNECT :PASSIVE
                     :REUSE-ADDRESS t)
     (LABELS ((next-connection ()
                (with-open-stream (stream (ACCEPT-CONNECTION socket :wait t))
                  (funcall handler stream))
                (next-connection)))
       (next-connection))))
只是

(LABELS ((next-connection ()
           (with-open-stream (stream (ACCEPT-CONNECTION socket :wait t))
             (funcall handler stream))
           (next-connection)))
  (next-connection)
优点:

  • 更简单、更少的代码
  • 不需要自递归函数
  • 不需要尾部调用优化来防止堆栈溢出
  • 减少源代码中的嵌套
  • 显式控制流构造明确了目的:这里是一个循环。读者不需要通过试图理解函数调用序列来从代码中推断它
您还可以将连接代码设置为函数,并且仍然使用一个简单的循环:

(loop
 (with-open-stream (stream (ACCEPT-CONNECTION socket :wait t))
   (funcall handler stream)))

函数和变量在Common Lisp中位于单独的名称空间中。您需要使用
FUNCALL
调用存储在变量中的函数。gah!我以前也这么做过。。。别忘了。非常感谢!Common Lisp是一个Lisp-2,您试图像Lisp-1一样使用它。函数和变量在公共Lisp中位于不同的名称空间中。您需要使用
FUNCALL
调用存储在变量中的函数。gah!我以前也这么做过。。。别忘了。非常感谢!Common Lisp是一个Lisp-2,您试图像Lisp-1一样使用它。它本身就有。啊-我知道我花了很长时间才把它打出来,@jkiiski把你整理好了-但我会把我的答案留给后代。是的,但你的答案涉及细节。谢谢。啊-我知道我花了很长时间才把这个打出来,@jkiiski帮你整理好了-但是我会把我的答案留给后代。是的,但是你的答案涉及到了细节。谢谢。接得好,我的第一个口齿不清是scheme。仍然习惯于常见的Lisp习惯用法和惯例。很好,我的第一个Lisp是scheme。仍然习惯于常见的Lisp习惯用法和惯例。