我是一个菜鸟李斯特,正在尝试使用Portacle的Adam的用于网络的Lisp教程。
我非常希望解释一下为什么下面的设置代码将愉快地运行,并将REPL游标更改为追溯游戏>如果在REPL中逐行输入,但如果在缓冲区中编译,则似乎无法工作。(第一次编译时,它经常抛出一个错误,说它找不到快速加载包;REPL游标从未改变。)
如果有人能说明这对编译后的程序意味着什么,那就太好了。我很难理解直接编程到REPL而不是保存的文件中的价值。如果在一个完整编译的程序是否包含下面的加载代码类型方面有任何noob级别的资源,那么一个链接就会让我感到高兴。谢谢。
(load "C:/Users/USER/portacle/all/quicklisp/quicklisp/setup.lisp")
(ql:quickload :cl-who)
(ql:quickload :hunchentoot)
(ql:quickload :parenscript)
(defpackage :retro-games
(:use :cl :cl-who :hunchentoot :parenscript))
(in-package :retro-games)
(defclass game ()
((name :initarg :name)
(votes :initform 0)))发布于 2020-11-04 08:30:33
要了解为什么这段代码是编译中的问题,请考虑编译器在编译包含它的文件时必须做些什么,在一个“冷”Lisp映像中,这里的“冷”意思是“没有Quicklisp加载”。要看这个,就把它分成几块。为了便于讨论,我们将设想文件编译器的工作方式是从文件中读取一个表单,编译它,然后写出它。为了我们的目的,它必须以一种等同于这个的方式工作,所以这里没问题。
第一块
(load "C:/Users/USER/portacle/all/quicklisp/quicklisp/setup.lisp")load是一个正常的函数,对它的调用发生在文件的顶层:编译器要做的是编译代码,以便在加载文件时调用load。编译器本身不会执行load,因此在编译时不会加载Quicklisp。
第二块
(ql:quickload :cl-who)
(ql:quickload :hunchentoot)
(ql:quickload :parenscript)这段代码有两个问题。在冷lisp中,QL包不存在,因为以前的load不是在编译时执行的,所以读取器在读取这些表单时会引发异常。汇编工作将在此结束。
如果Lisp不是冷的,特别是如果QL包确实存在(因此,如果正在进行编译的Lisp映像中加载了Quicklisp ),那么编译器将编写代码,使这三个ql:quickload调用在加载时发生,并且现在不会加载这三个QL系统。
在冷冰冰的口吻中,你将无法超越这一步。在编译时加载Quicklisp的Lisp中,您将看到。
第三块
(defpackage :retro-games
(:use :cl :cl-who :hunchentoot :parenscript))只有在编译时加载Quicklisp的Lisp中才能到达此块。这是一个包定义,它在编译时产生效果,这是它必须做的。但是,在编译时,第二个块中的调用尚未发生:这个包定义是指不存在的包。所以这是编译时的错误,编译就在这里结束。
如果进行编译的Lisp不仅有Quicklisp加载,而且还加载了三个QL系统,这将是成功的。
第四块
(in-package :retro-games)这将只在一个lisp中实现,在编译时,它同时加载了Quicklisp和三个QL系统。在这种情况下,它将告诉编译器将在retro-games包中读取以下表单。否则就永远达不到。
第五块
(defclass game ()
((name :initarg :name)
(votes :initform 0)))在不太可能发生的情况下,编译器会得到这样的结果,这就定义了一个名为retro-games::game的类。
问题是什么?
问题是编译器是一个编译器:它所做的是编译代码以供以后执行。但是,源的后面部分取决于已经加载的源的早期部分。
处理这个问题有两种方法。
如果您只编写了非常少量的代码,那么您可以告诉编译器,一些事情必须在编译时和加载时发生。您这样做的方式是eval-when,您想要的特别咒语是这样的,对于块1和2:
(eval-when (:compile-toplevel :load-toplevel :execute)
(load "C:/Users/USER/portacle/all/quicklisp/quicklisp/setup.lisp"))
(eval-when (:compile-toplevel :load-toplevel :execute)
(ql:quickload :cl-who)
(ql:quickload :hunchentoot)
(ql:quickload :parenscript))注意,您必须有两个独立的eval-when咒语,因为QL包需要由第一个包生成,以便可以读取第二个。
eval-when的语义有点多姿多彩,但是这个咒语可以做您想做的事情:它将告诉编译器加载这些东西,并确保它们在加载时也运行。
处理此问题的第二种方法(适合于较大的系统)是拥有一个或多个文件,这些文件为以后的文件构建编译时环境,并在诸如ASDF之类的东西的控制下,在后期文件之前编译和加载。在本例中,您通常需要一些最小的引导文件,这可能只需要确保加载Quicklisp,然后要求Quicklisp (因此也是ASDF)编译和加载其他所有内容,并由这些工具负责依赖关系管理,因此根本不存在ql:quickload。然而,如何设置这样的东西却超出了这个答案!
https://stackoverflow.com/questions/64673236
复制相似问题