【问题标题】:Why do many Common Lisp systems use a single packages.lisp file?为什么许多 Common Lisp 系统使用单个 packages.lisp 文件?
【发布时间】:2017-08-11 19:13:32
【问题描述】:

我看到的许多常用库都使用单个 packages.lisp 文件在一个地方声明库(系统)中的所有包。

由于导出的符号是包定义的一部分,这意味着单个源文件不会列出其导出的符号。

在我自己的项目中,我更喜欢每个包定义一个源文件,并在文件顶部定义其接口/导出的样式。

我想知道我是否做错了,或者错过了导致偏好单个 packages.lisp 文件的基本概念。

如果它是相关的,我也使用 ASDF 的 :package-inferred-system 方法和 uiop:define-package 而不是 defpackage,以利用它方便的符号阴影 :mix 功能——因为我还没有想到了解如何:use 一个隐藏内置符号的包,而无需在每个使用它的包中重新声明阴影。

【问题讨论】:

  • 我认为原因主要是历史原因 - 前defpackage 时代的遗留物,当时人们不得不跳过一些奇怪的圈子以确保包存在在文件中编译时间。

标签: common-lisp


【解决方案1】:

使用包的传统观点

有时package(符号命名空间)用于数十甚至数百个文件,可能需要计算包。这在一个文件中可能更简单,当包声明在一个文件中时,可能更容易获得文本概述。例如,文本编辑器的实现可能仅在一个使用大约 100 个文件的包中。另请注意,实际上是 Common Lisp 中的运行时数据结构,带有 programmer interface

来自 Java 等其他语言的影响

拥有一个包和一个对应源文件的样式通常来自 Common Lisp 之外,来自通常具有类似 one class = one namespace 之类的对应关系的语言em> = 一个文件。这会导致嵌套目录中存在大量文件,每个文件通常只有一小段代码。

Common Lisp 没有这些限制:方法没有组织在类中,类不是命名空间,文件可以有任何混合定义,...... Lisp 库往往有大包/命名空间和大文件。

结构及其局限性

Packages 在 Common Lisp 中是符号的命名空间。这不是一个成熟的模块系统。也没有实际的信息隐藏。符号和导出的符号是有区别的。另请注意,符号作为名称具有多种含义(变量、函数/宏/特殊运算符、类名、槽名、类型、数据对象、包名……),从包中导出符号并没有区别在这些含义之间。另请注意,可以但不建议在一个文件中使用多个包命名空间(例如,使用多个 in-package 表单)。通常,一个文件中只有一个命名空间。这通常由文件顶部某处的in-package 声明。

类没有命名空间。通常,类是使用内置的 Common Lisp 对象系统定义的,称为 CLOS。它们捆绑插槽并用于在 CLOS 通用函数中进行调度。但它们不包含它们的方法。

系统

系统不是语言结构。它们是 Common Lisp 的扩展。 系统 的概念由ASDF 等工具提供。系统是一种用于组织一堆文件的工具,这些文件构成了一个库/应用程序及其依赖项。它也是提供功能以在系统上使用操作(编译、加载、交付……)的地方。

???

为了更好地组织代码,可能缺少一些东西。每个项目可能需要稍微不同的方式。

如果需要,我通常会使用文件将相关功能放入一个文件并为系统设置一堆文件。但这可能意味着一个文件实现了多个类和许多功能。我倾向于在实现直接相关代码的部分中组织文件。我可能会在文件顶部描述一些元素(类、函数),但这更多的是局部概述,而不是导出符号的列表。一旦你用它的 IDE 将系统及其文件加载到 Lisp 中,开发环境的目的就是让我查询代码(在哪里?谁使用?使用什么?子/超类?包内容?.. .) 并为此提供浏览器。

还有其他组织代码的方法。例如,使用PROVIDEREQUIRE,在语言标准中只对它们进行了非常简单的描述。这些往往会按需引入功能并随时随地创建包结构。

可能需要类似面向对象的协议,它为 CLOS 提供更多结构。

MIT Lisp Machine 操作系统中包和系统的早期使用

70 年代末和 80 年代在麻省理工学院开发的 Lisp Machine 操作系统是为了避免名称冲突和组织代码的系统的早期需求之一。它是在 Lisp Machine Lisp 和后来的 Common Lisp 中开发的。在那里,许多不同的功能(编译器、编辑器、侦听器、检查器、邮件客户端、图形库、文件系统、串行接口、以太网接口、网络代码……)在一个可能有数万个地址空间中运行的符号。包声明通常在相应的系统描述文件中完成(这里我们再次使用 Lisp 的 system 含义作为库或应用程序,用于特定目的的文件集合)或有时在一个单独的文件。包为大型库甚至整个应用程序提供了命名空间。因此,文件、包、系统甚至类(以前称为 Flavor)已经被用来构建软件实现。请参阅 Lisp 机器手册(1984 年的版本),第 29 章,Maintaining Large Systems 和 1984 年的 Kent Pitman 的 MIT AI 备忘录 801:The Description of Large Systems。 Lisp 机器上的系统有 versions 并支持 patching(增量版本更改)。文件也有版本。

【讨论】:

  • 这是非常有用且内容丰富的背景。我是否可以安全地得出结论,今天使用一个包一个文件的方法只是一个选择问题,并且不提供 packages.lisp 文件不会产生负面影响(就 Lisp、ASDF、Quicklisp 等而言)?跨度>
  • @anticrisis:只是它不适合通常的 Lisp 风格。使用大量带有每个文件命名空间的小文件几乎没有优势。最后,它比使用更大的包更令人困惑。由于 Lisp 不提倡严格的信息隐藏,因此在 Lisp 中模仿 class=namespace=file 编程风格几乎没有意义。
  • 我明白了——我想知道如何协调一个跨越一百个文件的单一全局命名空间的想法,具有模块化、关注点分离、具有清晰外部 API 的子系统等。但我不知道认为你提出的极端,要么。像往常一样,Common Lisp 中似乎有很多功能,由团队/用户设计一个最适合他们需求的系统。
  • packages.lisp 文件通常也可以很好地概述系统。从theseexamples 可以看出,符号是按逻辑分组的,很容易看到包昵称、导入、阴影和阴影导入。
猜你喜欢
  • 2019-01-23
  • 2019-01-18
  • 1970-01-01
  • 2015-07-03
  • 2015-01-20
  • 2011-03-20
  • 2021-08-23
  • 1970-01-01
  • 2019-05-10
相关资源
最近更新 更多