是否有Prolog的包管理器?

Wou*_*eek 9 module package-managers prolog swi-prolog git-submodules

我想知道与其他程序员共享Prolog代码/库的最佳实践(以及多个项目之间的自己).我自己也在使用SWI-Prolog,但也对其他Prolog如何解决这个问题感兴趣.

相比之下,Java有Maven + JAR,Python有EasyInstall + PythonEggs,其他语言可能还有很多其他语言.但Prolog还有吗?

SWI-Prolog包

在SWI-Prolog中有Packs,由模块支持library(prolog_pack).这些的缺点是:

  1. 您必须为每个包创建存档文件或Git存储库.说我想创建10包.现在我需要创建10个Git存储库.我有时会编辑影响多个文件,可能驻留在多个包/ repos中,要求我为单个(多文件)编辑提交几个Git存储库.
  2. 为了创建一个包,你必须手工挑选一些"属于一起"的文件.有时候我发现文件X属于包A和包B.现在我需要在存储库A和B中维护文件X的副本,或者我需要创建另一个包C只包含X和导入C到A和B.
  3. 包在公共网站上发布.我的大部分图书馆对我来说都很有趣.其中一些对我与之合作的特定人员很有意思,只有少数人准备好进行更广泛/公开的传播.
  4. 包维护者必须指定包间依赖关系.对于复杂的图书馆等级,对我来说似乎是不必要的工作.我已经非常严格地使用Prolog模块,并且只想使用Prolog模块导入的层次结构作为依赖图.

Git子模块

另一种我直到现在使用过的方法是Git子模块.通过将一个存储库导入另一个存储库来实现库之间的依赖关系.这与SWI-Prolog包有一些相同的缺点:

  1. 每个库的Git存储库,因此需要维护大量存储库.
  2. 维护者必须明智地选择每个repo的文件,并且必须指定需要哪些Git子模块包含.
  3. 更新现有库非常困难.我发现(困难的方法)我交给代码的大多数人都无法成功更新具有许多错综复杂的相互依赖的子模块导入的Git存储库.(我非常尊重偶尔使用子模块的Git大师并且总是把它做对,但是大多数非程序员和我工作的很多程序员都觉得它太难了.)

我的理想方法

我个人对完美的Prolog代码共享方法的偏好是:

  1. 您传播的库的数量和您拥有的Git存储库的数量是独立的.具体来说,我可以有一个相当大的存储库,其中的一部分以不同的方式传播.如果有人喜欢(重新)使用我的Prolog模块和DCG帮助器谓词,那么我可以简单地向该人传播该单个文件(加上潜在的依赖关系).
  2. 您不必亲自挑选和手动复制单个文件,而是让算法遍历模块导入的层次结构以提取(显然)属于一起的文件.首次运行程序时会下载文件.这些文件可能都属于同一个Git存储库或多个存储库,算法根本不关心存储库和库之间或存储库和文件之间的映射.
  3. 代码的维护者能够决定一个库是公开发布还是发布给有限的一组人(或者只限于包括维护者在内的有限组).
  4. 文件之间的模块导入层次结构是依赖关系跟踪所需的全部内容.

以上暗示我理想的库共享方法是基于文件的,而不是基于包的.如果Prolog模块A使用Prolog模块B并且加载了A,则从本地文件(如果存在)加载B或从存储库下载B. 我不确定基于文件的方法在其他语言中有多常见.前面提到的Maven + JAR和EasyInstall + PythonEggs都是基于包的.

我对其他Prolog程序员使用和思考这个主题非常感兴趣!

小智 2

我想这样一个简单的遍历算法可以给你一个模块的集合,如果你已经注释了那些属于包的模块和那些不属于包的模块。它将产生尚不属于包的模块子集。

但我有一种感觉,这没有抓住重点。我认为软件包的软件工程与简单地交付一个软件包有着不同的目标。通常,一个人会面对多个包,并且这些包可能具有依赖关系,这些依赖关系植根于模块本身的依赖关系。

数学上:

   M: The set of modules
   P: The set of packages
   p(m): The package a module belongs to or null.
Run Code Online (Sandbox Code Playgroud)

因此,如果我有模块依赖项,我可以从中派生包依赖项:

   d(m1,m2): The module m1 depends on the module m2
   d'(p1,p2): The package p1 depends on the package p2

   d'(p1,p2) <=> exists m1,m2 (p(m1)=p1 & p(m2)=p2 & d(m1,m2))
Run Code Online (Sandbox Code Playgroud)

您的算法可能会派生一个包 p,然后它可能依赖于一些已用于注释现有模块的包 p1, .., pm。但是软件工程已经找到了很多识别多个包的方法,典型的架构是垂直分层、水平分层等。也许也有相应的算法。

但事情并没有那么简单。包通常被定义为帮助模块的共同演化并促进变更管理和发布管理。如果模块共同进化,则不希望一个接一个地释放模块。想要发布一组达到相同进化级别的模块,让这组模块能够卓有成效地交互。

但如果我们有模块的演变,我们也会有包的演变。如果您只有一个软件包,或者您更多地使用多个软件包来存储您的东西,这种演变就会发生。我不确定 Prologs 的现有软件包系统是否已经在这里提供帮助。我所看到的 SWI-Prolog 是包的版本控制和包的待办事项列表:
http://www.swi-prolog.org/howto/PackTodo.txt

上述待办事项都很有意义。但它们并没有直接解决包依赖性及其演变。在 Jekejeke Prolog 中,我目前正在尝试改进模块依赖性。例如,最终用户可以通过以下命令加载模块 clpfd:

   ?- use_module(library(clpfd)).
Run Code Online (Sandbox Code Playgroud)

如果安装并激活了包含模块 clpfd 的软件包,则该命令将成功。如果未安装此类软件包或安装了软件包但尚未激活,则该命令将失败。主包和模块 clpfd 将使用其他模块和包。如果它使用其自己的包本地的模块,则可以按如下方式执行,不需要library/1:

   ?- use_module(helper).
Run Code Online (Sandbox Code Playgroud)

但是,如果它使用的模块不是其自己的包的本地模块,那么它通常会采取不同的做法。例如,模块 clpfd 可能使用模块 apply。它将对 Library/1 执行此操作:

   ?- use_module(library(apply)).
Run Code Online (Sandbox Code Playgroud)

现在我们认识到,通过检查 clpfd 或辅助模块,我们无法知道它何时从何处获取 apply 模块执行上述操作。只有当我们手头有一组特定的包并且我们解析适用于其包的模块名称时,我们才知道包依赖关系。

这种灵活性有其优点和缺点。缺点是我们无法建立固定的包依赖关系。并且依赖于固定包依赖项的版本控制等工具将无法工作。因此,解决方案是从模块的版本控制引导包的版本控制,类似于我们如何从模块的依赖关系导出包之间的依赖关系。

但我还不确定这将如何运作。如果我们能够区分公共模块和私有模块,那么复杂度肯定会降低。例如,上面的模块助手可以仅由 clpfd 使用,并且在确定包依赖项和包版本控制时可以省略。

到目前为止我的想法:

  • 从模块派生包依赖关系
  • 从模块派生包版本控制
  • 允许包内包含私有和公共模块。

再见