我必须用 Lisp 写一个游戏。为了清楚起见,我想将代码拆分为不同的 .lisp 文件。
如何从另一个文件中的函数中调用函数?
例如,file1.lisp 有一个名为 function1 的函数,而 file2.lisp 有一个名为 function2 的函数。如何从函数 1 中调用函数 2?
谢谢!
我必须用 Lisp 写一个游戏。为了清楚起见,我想将代码拆分为不同的 .lisp 文件。
如何从另一个文件中的函数中调用函数?
例如,file1.lisp 有一个名为 function1 的函数,而 file2.lisp 有一个名为 function2 的函数。如何从函数 1 中调用函数 2?
谢谢!
正如你所知,有多种不同的 Lisp 系统。我将发布 Common Lisp 的答案。
天真的方法是使用(load "filename.lisp")
,但一段时间后它并不能很好地工作。所以...
Common Lisp 有一个名为“ASDF”的库,用于处理打包和文件管理。ASDF 有一些设置。
我在我的.sbclrc
文件中使用它(假设我在 ~ 中创建了一个 .asdf 文件):
(pushnew "~/.asdf/" asdf:*central-registry* :test #'equal)
我通常使用以前构建的 ASDF 文件,然后对其进行修改。
这是一个示例 ASDF 文件的内容:
(asdf:defsystem #:cl-linq
:depends-on ( #:alexandria #:anaphora)
:components ((:file "cl-linq"))
:name "cl-linq"
:version "0.1"
:maintainer "Paul Nathan"
:author "Paul Nathan"
:licence "LLGPL"
:description "CL LINQ style interface with strains of SQL"
:long-description
"DSL for managing and querying datasets in a SQL/LINQ style
syntax. cl-linq provides a simple and usable set of primitives to
make data examination straightforward. ")
我将此代码放在cl-linq.asd
源代码旁边的文件中(cl-linq.lisp
来自"cl-linq"
defsystem 中的组件),然后将cl-linq.asd
文件符号链接到我的~/.asdf/
目录。
在我的 cl-linq.lisp 文件中,我包含以下内容:
(defpackage :cl-linq
(:use
:common-lisp
:anaphora)
(:export
#:query
#:cl-linq-select))
(in-package :cl-linq)
因此,对于您的情况,我将有 2 个组件;每个都有自己的 defpackage 形式,将其他包需要的功能导出。
对于示例,我从我的一个项目CL-LINQ中获取了代码。您可以完全自由地将其用作模板。
这适用于 Emacs Lisp(又名 elisp)
在此位置创建文件: ~/.emacs.d/init.el
在此位置创建文件: ~/.emacs.d/file1.el
在此位置创建文件: ~/.emacs.d/file2.el
现在,打开~/.emacs.d/init.el
并写入(然后保存):
(load "~/.emacs.d/file1.el")
(load "~/.emacs.d/file2.el")
(defun run-both-functions ()
(interactive)
(switch-to-buffer "*Messages*")
(first-function)
(sit-for 2)
(second-function))
现在,打开~/.emacs.d/file1.el
并写入(然后保存):
(defun first-function ()
(message "My name is Fred."))
现在,打开~/.emacs.d/file2.el
并写入(然后保存):
(defun second-function ()
(message "My name is George."))
现在,重新启动 Emacs 并输入: M-x run-both-functions RET
您放入上述三 (3) 个文件中的任何一个的任何功能都可以被其他功能访问。您会注意到其中run-both-functions
包含一个(interactive)
语句,这意味着用户可以使用M-x
键盘快捷键或键盘快捷键调用该函数。
如果您使用函数加载,则不指定文件类型会很有用。
加载文件:fasl 或 source
而不是(load "foo.lisp")
一个可以调用(load "foo")
。通常,Common Lisp 提供将 Lisp 文件编译为fasl(快速加载)文件的功能。这些通常是预编译的字节码或本机代码。通常,如果存在文件,Common Lisp 实现将加载已编译的代码。这样可以节省时间(因为编译后的代码通常可以比 Lisp 源代码更快地加载)并且代码通常更快(因为文件编译器已经编译了它)。
如果编译文件较新,通常使用函数加载编译文件,或者首先将源文件编译为新的编译文件。
根据正在加载的当前文件加载文件
在(load "foo")
文件foo
中不是一个完整的文件名。例如,我们不知道加载它的目录。这取决于*default-pathname-defaults*
当前目录的值或在某些实现中的值(对于 Unix 系统是典型的)。根据我们当前正在加载的文件加载文件可能很有用 - 如果加载一个文件会触发更多文件被加载。对于这个 Common Lisp 有变量*load-pathname*
和*load-truename*
(这是文件系统使用的真实文件名)。
加载文件foo与当前加载的文件调用相同的目录:
(load (merge-pathnames "foo" *load-pathname*))
要在与当前加载的文件调用相同的目录的子目录bar中加载文件foo :
(load (merge-pathnames "bar/foo" *load-pathname*))
使用 Common Lisp,我是这样完成的:
在file1.lisp
我定义一个函数sayHello
并在包名下导出该函数helloLisp
(defpackage :helloLisp
(:use :common-lisp)
(:export #:sayHello))
(in-package :helloLisp)
(defun sayHello () (print "Hello!"))
在文件中file2.lisp
我require
这个文件是这样的:
(require "helloLisp" "./file1.lisp")
(helloLisp:sayHello)
使用 SBCL 1.4.11 测试