转载自:https://mp.weixin.qq.com/s/aZ8fhJMsv8pTZL2Wvoch-w
本章涉及文件处理和模块化的各个方面。我们将学习三个知识点:
1.谓词定义如何分布在不同文件中。
2.如何编写模块化软件系统。
3.如何将结果写入文件以及如何从文件读取输入。
1通过文件分割程序
在这一阶段,您已经编写了许多使用谓词append / 3和member / 2的程序。每次需要其中一个时,您可能要做的就是回到定义并将其复制到要使用它的文件中。也许,在做了几次之后,您开始认为一次又一次地复制相同的谓词定义是很烦人的——如果您可以在某个地方一劳永逸地定义它们,然后简单地访问它们,那将是多么令人愉快的事情。只要您需要它们。好吧,这听起来像是一件很明智的事情,当然,Prolog为您提供了实现的方法。
读取程序
实际上,您已经知道一种告诉Prolog读取存储在文件中的谓词定义的方法,即
[FileName1]
命令。您一直以来都在使用这种形式的查询来告诉Prolog读取文件。但是,您还应该了解两个有用的信息。首先,您可以说
[FileName1,FileName2,…,FileNameN]
其次,更重要的是,文件读取不必交互进行。如果你把
:- [FileName1,FileName2,…,FileNameN].
放在程序文件(例如main.pl)的顶部,您告诉Prolog在继续读取其余程序之前,先读取列出的文件。
此功能为我们提供了重用定义的简单方法。例如,假设您将所有用于基本表处理的谓词定义(例如append / 3,member / 2,reverse / 2等)保留在名为listPredicates.pl的文件中。如果要使用它们,只需输入
:- [listPredicates].
在包含需要它们的程序的文件顶部。当读入该文件时,Prolog将查阅listPredicates,并且listPredicates中的所有谓词定义均可用。
您应该了解一个实用点。 Prolog加载文件时,通常不会检查是否确实需要读取文件。如果其中一个文件提供的谓词定义已经存在于数据库中(因为先前已查询过该文件),则Prolog仍会再次查询该文件,尽管不需要。如果您正在查询非常大的文件,这可能会很烦人。
在这方面,内置谓词sure_loaded / 1的行为更加智能。它的工作原理如下。遇到以下指令
:- ensure_loaded([listPredicates]).
Prolog检查文件listPredicates.pl是否已经加载,并且仅在自上次加载以来已更改的情况下才重新加载。
模块
现在,假设您正在编写一个管理电影数据库的程序。您已经设计了一个谓词printActors来显示特定电影中主演的所有演员,还设计了一个谓词printMovies来显示由特定电影制片人导演的所有电影。这两个定义都存储在不同的文件中,即printActors.pl和printMovies.pl,并且都使用辅助谓词displayList / 1。下面第一个文件:
% This is the file: printActors.pl
printActors(Film):-
setof(Actor,starring(Actor,Film),List),
displayList(List).
displayList([]):- nl.
displayList([X|L]):-
write(X), tab(1),
displayList(L).
下面是第二个文件
% This is the file: printMovies.pl
printMovies(Director):-
setof(Film,directed(Director,Film),List),
displayList(List).
displayList([]):- nl.
displayList([X|L]):-
write(X), nl,
displayList(L).
请注意,