5
?- assertz(:- module(foo1, [f/1])).
true.

?- foo1:assertz(f(1)).
true.

?- foo1:f(1).
true.

?- foo2:f(1).
Correct to: "foo1:f(1)"? no
ERROR: Undefined procedure: foo2:f/1
ERROR: In:
ERROR:    [8] foo2:f(1)
ERROR:    [7] <user>

我感觉合理。但是后来(从头开始)....

?- assertz(:- module(foo1, [f/1])).
true.

?- assertz(f(1)).
true.

?- foo1:f(1).
true.

?- foo2:f(1).
true.    # Wait, what? foo2 doesn't appear in my program. Should fail?

?- frobnoz:f(1).
true.    # Also odd!

但是之后...

?- foo2:assertz(f(1)).
true.

?- foo2:f(1).
true.

?- frobnoz:f(1).
ERROR: Undefined procedure: frobnoz:f/1

foo2当我不提foo2. 为什么frobnoz:f第二个例子成功,第三个例子失败?

什么是模块?我以为它们是名称空间,但现在很困惑。

4

1 回答 1

7

第一个问题:

当我没有提到 foo2 时,f 如何被添加到 foo2。

来自SWI-Prolog 手册 - 模块自动加载部分

SWI-Prolog 默认支持从其标准库自动加载。自动加载意味着当在执行期间发现谓词丢失时,将搜索库并使用 use_module/2 延迟导入谓词。

您可以更深入,但基本上,当模块没有明确定义时,prolog 搜索它并静默加载它。这是默认行为。您可以使用autoload flag更改它。

第二个问题:

为什么 frobnoz:f 在第二个示例中成功,但在第三个示例中失败?

可能这frobnoz:f可以作为foo1模块的依赖项找到,您在第三个示例中没有引用它。

第三个问题:

什么是模块?我以为它们是名称空间,但现在很困惑。

正如SWI-Prolog 参考手册所述:

Prolog 模块是谓词的集合,它通过一组提供的谓词和运算符定义公共接口。Prolog 模块由 ISO 标准定义。不幸的是,该标准被认为是失败的,据我们所知,它没有被任何具体的 Prolog 实现所实现。SWI-Prolog 模块系统语法源自 Quintus Prolog 模块系统。Quintus 模块系统已成为 SICStus、Ciao 和 YAP 等多个主流 Prolog 系统的模块系统的起点。SWI-Prolog 模块系统的底层原语与上述系统不同。这些原语允许文件中的多个模块、分层模块、模拟其他模块接口等。(来源

在经典的 Prolog 系统中,所有谓词都组织在一个命名空间中,任何谓词都可以调用任何谓词。[...] Prolog 模块封装了一组谓词并定义了一个接口。模块可以导入其他模块,这使得依赖关系明确。给定明确的依赖关系和定义良好的接口,在不破坏整个应用程序的情况下更改模块的内部组织变得更加容易。(来源

通常,模块的名称与定义它的文件的名称相同,没有文件扩展名,但不强制执行此命名。模块被组织在一个单一的平面命名空间中,因此必须小心选择模块名称以避免冲突。正如我们将看到的,模块系统的典型应用很少在源文本中明确使用模块的名称。(来源

于 2020-05-10T10:09:41.687 回答