我必须用Lisp写一个游戏。为了说清楚,我想将代码拆分为不同的.lisp文件。
如何从另一个文件中的函数调用函数?
E.g。 file1.lisp有一个名为function1的函数,file2.lisp有一个名为function2的函数。 如何从function1调用function2?
谢谢!
答案 0 :(得分:5)
您知道,有各种不同的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
中(来自defsystem中组件cl-linq.lisp
的{{1}}),然后将"cl-linq"
文件符号链接到我的cl-linq.asd
目录。
在我的cl-linq.lisp文件中,我包括:
~/.asdf/
所以对于你的情况,我会有2个组件;每个都有自己的defpackage形式,导出功能,而另一个包需要。
对于这些例子,我采用了CL-LINQ的代码,这是我的一个项目。您可以将其用作模板。
答案 1 :(得分:1)
这适用于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
或键盘快捷方式调用该函数。
答案 2 :(得分:0)
如果使用函数load,则不指定文件类型会很有用。
加载文件:fasl或来源
而不是(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*))
答案 3 :(得分:0)
我用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测试