首页 > 解决方案 > 以编程方式加载 Common Lisp 模块

问题描述

几周前我刚开始学习 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

解决方案


包和系统的快速总结

“加载为”在 Common Lisp 中没有意义,因为加载与定义新系统或包不同。在 Python 中,文件是模块等,但在 Lisp 中不是。

Lisp 有一个的概念,它们是命名空间。它们用于组织符号(符号是一等值)。换句话说,他们使用、导出或可能来自其他包的影子符号,仅此而已。当您评估 时(in-package pack),您可以直接写入所有可访问的符号pack,例如my-fun,否则您需要完全限定符号,例如some-package:their-func。有一些扩展允许您导入具有不同名称的包,但这不是标准的(请参阅https://github.com/phoe/trivial-package-local-nicknames

加载 Lisp 脚本不一定与定义包相同,它取决于文件中的内容(如果它是defpackage表单)。

当您想在 Lisp 中组织源代码时,您可以使用ASDF定义一个系统。一个系统列出了它的所有依赖关系、它的组件(文件)以及它们的组件之间的依赖关系。这就是您描述文件应按哪些顺序加载、编译、测试等的方式。

包和系统是独立的,但在小型系统中,您通常具有相同的系统名称和它定义的唯一包。对于较大的系统,可能有多个包。

请参阅21. 大型编程:包和符号

你的问题

您的每个文件都需要定义一个包,以避免污染单个命名空间,例如:

(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*))

推荐阅读