Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Common lisp 如何避免此编译错误?_Common Lisp_Eval_Sbcl - Fatal编程技术网

Common lisp 如何避免此编译错误?

Common lisp 如何避免此编译错误?,common-lisp,eval,sbcl,Common Lisp,Eval,Sbcl,我有生成代码的代码(比如sayhello),我发现用生成的代码生成函数的最简单方法是将defun放入eval中,如下所示: (打招呼() `(普林斯“测试”) (评估 `(defun测试() (打招呼) (测试) 此文件在命令行上运行良好: sbcl --script test.lisp 但当我试图在SBCL内部编译它时,会抱怨: * (compile-file "test.lisp") ; compiling file "test.lisp" (written 19 APR 2018 0

我有生成代码的代码(比如
sayhello
),我发现用生成的代码生成函数的最简单方法是将
defun
放入
eval
中,如下所示:

(打招呼()
`(普林斯“测试”)
(评估
`(defun测试()
(打招呼)
(测试)
此文件在命令行上运行良好:

sbcl --script test.lisp
但当我试图在SBCL内部编译它时,会抱怨:

* (compile-file "test.lisp")

; compiling file "test.lisp" (written 19 APR 2018 01:05:19 PM):
; compiling (DEFUN SAY-HELLO ...)
; compiling (EVAL (SB-INT:QUASIQUOTE #))
; compiling (TEST)
; file: test.lisp
; in: TEST
;     (TEST)
;
; caught STYLE-WARNING:
;   undefined function: TEST
;
; compilation unit finished
;   Undefined function:
;     TEST
;   caught 1 STYLE-WARNING condition

; test.fasl written
; compilation finished in 0:00:00.031
#P"test.fasl"
T
NIL
*

有没有办法编写代码来避免这个编译错误?从生成代码的函数中创建代码有更好的习惯用法吗?

函数与宏-文件编译器

文件编译器对函数和宏定义的处理略有不同:

  • 功能:文件编译器编译它们并可以使用有关它们的信息。它将生成的代码转储到编译的fasl文件中。但它不会在编译时环境中创建可执行定义

  • 宏:文件编译器编译它们并使它们在编译时环境中可用。因此,编译器可以使用同一文件中较早定义的宏来扩展该宏在同一文件中的使用

编译文件时表单的情况

  • :compile top level->file compile在编译文件且表单处于顶级时对其进行评估

  • :load toplevel->文件编译器生成代码,以便在加载期间执行toplevel表单

您的代码

如果要在定义函数的同一文件中使用该函数,则需要告诉编译器在编译时实际执行该定义:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun fn-say-hello ()
    `(princ "test")))
稍后在文件中,宏可以使用该函数。编译器自动知道宏定义,但不知道函数

(defmacro say-hello ()
  (fn-say-hello))  ; this is a function call, not returned code
之后,您可以在文件中使用此宏。然后,编译器将展开该宏并运行函数
fn say hello
——然后该函数就可以运行了,因为我们之前已经向编译器介绍了该函数

(defun test ()
  (say-hello))

(test)

在玩了EVAL-WHEN之后,我还意识到我可以使用
#.
读卡器宏,而不是定义一次性宏:

;;EVAL-WHEN使sayhello在编译时可用
(在(:编译顶级:加载顶级:执行)时求值)
定义我们想要使用的函数
(德芬打招呼()
`(普林斯“测试”))
(defun测试()
#(打招呼);eval在编译时就地打招呼
(测试)

因此,如果
test
被定义为宏,我需要在
say hello
周围放置一个
EVAL-WHEN
,告诉它在编译时使其可用,但如果两者都是函数(第二个
EVAL
d)然后我需要将这两个函数放在一起,使其在编译时发生。@GustavBertram:需要知道文件中要使用的所有函数,例如在宏扩展期间。要么更早地加载它们,要么确保它们有一个EVAL-WHEN情况。这只在简单的情况下有用,在这种情况下,生成函数没有参数,因为它看起来不像宏扩展环境,因为它是在宏扩展之前完成的。