以编程方式加载 Common Lisp 模块
Load Common Lisp Module Programmatically
我几周前才开始学习 Common Lisp,如果这是一个显而易见的问题,我深表歉意。如何以编程方式加载模块?我有一个“任务”目录,每个都是一个 Lisp 程序,我想导入每个和 运行 它们都包含的特定函数。
我找到了一种遍历目录的方法(通过 UIOP:DIRECTORY-FILES
)。但是我一直在试图找出一种方法来将模块“作为”特定名称加载,如 Python 中所示。这将允许我 load "module-1.lisp" as mod
然后 load "module-2.lisp" as mod
循环。
伪代码:
for path in directory
(load path as mod)
(mod:function)
如果有更好的方法来实现我想要做的事情,请尽管说出来!在此先感谢您的帮助!
软件包和系统的快速摘要
"加载为" 在 Common Lisp 中没有意义,因为加载与定义新系统或包不同。在 Python 中,文件是模块等,但在 Lisp 中不是。
Lisp 有一个 packages 的概念,它们是名称空间。它们用于组织符号(符号是第一个-class值)。换句话说,他们使用、导出或可能隐藏来自其他包的符号,仅此而已。当你计算 (in-package pack)
时,你可以直接从 pack
中写出所有 可访问的 符号,如 my-fun
,否则你需要完全限定符号,如 some-package:their-func
。
有些扩展允许您导入具有不同名称的包,但这不是标准的(参见 https://github.com/phoe/trivial-package-local-nicknames)
加载 Lisp 脚本不一定与定义包相同,它取决于文件中的内容(如果它是 defpackage
形式)。
当您想用 Lisp 组织源代码时,您可以使用 ASDF 定义一个 系统。一个系统列出了它的所有依赖关系,它的组件(文件)以及它们的组件之间的依赖关系。这就是您如何描述文件应该以何种顺序加载、编译、测试等。
包和系统是独立的,但在小型系统中,系统通常具有相同的名称和它定义的唯一包。对于较大的系统,可能有多个包。
参见 21. Programming in the Large: Packages and Symbols。
你的问题
您的每个文件都需要定义一个包,以避免污染单个命名空间,例如:
(defpackage :common-name.01
(:use :cl :utils)
(:export #:run-me))
(in-package :common-name.01)
;; some code
但是一旦它们全部加载完毕,无论是使用您的方法还是通过定义适当的 ASDF 系统,您都希望能够访问所有包中的所有 RUN-ME
功能。
您可以编写一些列出包等的内省代码,但我认为更好的方法是让每个文件都有一种方法声明它们的RUN-ME
函数应该像测试框架一样在您的框架中注册。
例如,在文件末尾,您可以写:
(provide-function 'run-me)
这假设例如您的 utils
包定义并导出一个名为 provide-function
的函数,该函数将值存储在中央注册表中。
例如,在utils.lisp
中:
(defpackage :utils
(:use :cl)
(:export #:provide-function
#:run-all))
(in-package :utils)
(defvar *all-interesting-functions* nil)
(defun provide-function (f)
(pushnew f *all-interesting-functions* :test #'eql))
当你想要运行所有函数时,你可以遍历这个列表:
(defun run-all ()
(mapcar #'funcall *all-interesting-functions*))
我几周前才开始学习 Common Lisp,如果这是一个显而易见的问题,我深表歉意。如何以编程方式加载模块?我有一个“任务”目录,每个都是一个 Lisp 程序,我想导入每个和 运行 它们都包含的特定函数。
我找到了一种遍历目录的方法(通过 UIOP:DIRECTORY-FILES
)。但是我一直在试图找出一种方法来将模块“作为”特定名称加载,如 Python 中所示。这将允许我 load "module-1.lisp" as mod
然后 load "module-2.lisp" as mod
循环。
伪代码:
for path in directory
(load path as mod)
(mod:function)
如果有更好的方法来实现我想要做的事情,请尽管说出来!在此先感谢您的帮助!
软件包和系统的快速摘要
"加载为" 在 Common Lisp 中没有意义,因为加载与定义新系统或包不同。在 Python 中,文件是模块等,但在 Lisp 中不是。
Lisp 有一个 packages 的概念,它们是名称空间。它们用于组织符号(符号是第一个-class值)。换句话说,他们使用、导出或可能隐藏来自其他包的符号,仅此而已。当你计算 (in-package pack)
时,你可以直接从 pack
中写出所有 可访问的 符号,如 my-fun
,否则你需要完全限定符号,如 some-package:their-func
。
有些扩展允许您导入具有不同名称的包,但这不是标准的(参见 https://github.com/phoe/trivial-package-local-nicknames)
加载 Lisp 脚本不一定与定义包相同,它取决于文件中的内容(如果它是 defpackage
形式)。
当您想用 Lisp 组织源代码时,您可以使用 ASDF 定义一个 系统。一个系统列出了它的所有依赖关系,它的组件(文件)以及它们的组件之间的依赖关系。这就是您如何描述文件应该以何种顺序加载、编译、测试等。
包和系统是独立的,但在小型系统中,系统通常具有相同的名称和它定义的唯一包。对于较大的系统,可能有多个包。
参见 21. Programming in the Large: Packages and Symbols。
你的问题
您的每个文件都需要定义一个包,以避免污染单个命名空间,例如:
(defpackage :common-name.01
(:use :cl :utils)
(:export #:run-me))
(in-package :common-name.01)
;; some code
但是一旦它们全部加载完毕,无论是使用您的方法还是通过定义适当的 ASDF 系统,您都希望能够访问所有包中的所有 RUN-ME
功能。
您可以编写一些列出包等的内省代码,但我认为更好的方法是让每个文件都有一种方法声明它们的RUN-ME
函数应该像测试框架一样在您的框架中注册。
例如,在文件末尾,您可以写:
(provide-function 'run-me)
这假设例如您的 utils
包定义并导出一个名为 provide-function
的函数,该函数将值存储在中央注册表中。
例如,在utils.lisp
中:
(defpackage :utils
(:use :cl)
(:export #:provide-function
#:run-all))
(in-package :utils)
(defvar *all-interesting-functions* nil)
(defun provide-function (f)
(pushnew f *all-interesting-functions* :test #'eql))
当你想要运行所有函数时,你可以遍历这个列表:
(defun run-all ()
(mapcar #'funcall *all-interesting-functions*))