如何使用Prolog中几个模块共享相同名称的谓词

时间:2018-01-10 16:27:32

标签: prolog swi-prolog

我是Prolog的新手,我正在使用SWI-Prolog来解决以下问题。 我有几个文件dataBase1.pldataBase2.pl,...具有相同的结构 (基于此thread

:- module(dataBase1,[]).

:- use_module(library(persistency)).

:- persistent 
       predicate1(A:any, B:any),
       predicate2(A:any, B:any).

:- initialization(init).

init :-
        absolute_file_name('dataBase1.db', File, [access(write)]),
        db_attach(File, []).

predicate1/2, predicate2/2对所有数据库文件都是通用的。

然后,我在第三个文件predicates.pl中定义了几个使用以前数据库中的子句的子句,例如testPredicate(A,B) :- predicate1(A,B), predicate2(A,B).

我的问题是我希望上面的子句使用与数据库文件对应的所有模块中的predicate1/2, predicate2/2。 在当前状态下,我需要精确上下文模块才能使用 predicate1/2, predicate2/2(即dataBase1:predicate1/2, dataBase2:predicate1/2,...。)

我无法使用use_module/1,因为我会动态添加/删除数据库文件。

提前感谢任何建议!

编辑:在评论中讨论之后,如何将head(X,Y) :- body()形式的可查询谓词定义为持久动态谓词?

2 个答案:

答案 0 :(得分:1)

iirc,您应该使用模块名称作为前缀(以冒号分隔)来调用谓词。

http://www.swi-prolog.org/pldoc/man?section=overrule

答案 1 :(得分:0)

Prolog模块没有为您要实现的设计模式提供明智的解决方案。这种设计模式有时称为“许多世界”模式。但是,您可以在其他Logtalk对象中轻松地做到这一点(您可以使用大多数Prolog编译器(包括SWI-Prolog)运行Logtalk。

首先,定义一个根对象,该对象声明您的数据库谓词:

:- object(database).

    :- public([predicate1/2, predicate2/2]).
    :- dynamic([predicate1/2, predicate2/2]).

:- end_object.

您可以具有任意数量的扩展该对象的数据库对象。要将文件与每个单独的数据库/对象相关联,可以在装入文件时简单地使用include/1指令将文件的内容装入相应的对象。例如:

:- object(db1, extends(database)).

    :- include('db1.db').

:- end_object.


:- object(db2, extends(database)).

    :- include('db2.db').

:- end_object.

您还可以轻松创建动态数据库:

...,
% ensure the corresponding file exists
open(write, 'db42.db', Stream),
close(Stream),
% create the dynamic database object    
create_object(db42, [extends(database)] [include('db42.db')], []),
...

您还希望能够使用不同的数据库进行推断:

  

然后,我在第三个文件predicates.pl中定义了几个子句   利用先前数据库中的子句,例如   testPredicate(A,B):-谓词1(A,B),谓词2(A,B)。

您可以通过在根对象中定义testPredicate/2谓词轻松地做到这一点,该谓词变为:

:- object(database).

    :- public([predicate1/2, predicate2/2]).

    :- public(testPredicate/2).
    testPredicate(A,B) :-
        ::predicate1(A,B),
        ::predicate2(A,B).

:- end_object.

::/1是Logtalk的自已消息控制结构。这意味着在一个目标中,例如:

?- db1::testPredicate(A,B).

在目标中,predicate1/2predicate2/2将在db1中被调用:

?- db2::testPredicate(A,B).

predicate1/2predicate2/2将在db2中被调用。要修改数据库动态谓词,只需使用断言和撤回消息到数据库对象。例如:

?- db42::assertz(predicate1(foo,bar)).
...

最后,您要保留数据库动态谓词。我们可以例如在根对象上添加一个谓词,以将所有数据库保存到相应的文件中。例如(假设数据库谓词从句是事实):

    :- public(save/0).
    save :-
        this(This),
        forall(
            extends_object(Database, This),
            save(This)
        ).

    save(Database) :-
        atom_concat(Database, '.db', File),
        open(File, write, Stream),
        save_predicates(Database, Stream),
        close(Stream).

    save_predicates(Database, Stream) :-
        current_predicate(Functor/Arity),
        functor(Template, Functor, Arity),
        predicate_property(Template, (dynamic)),
        write_canonical(Stream, (:- dynamic(Functor/Arity))), write('.\n),
        Database::clause(Template, true),
        write_canonical(Stream, Template), write('.\n),
        fail.
    save_predicates(_, _).

要保存所有数据库,只需调用目标database::save。请注意,草绘的解决方案是完全可移植的。您可以使用任何Logtalk支持的Prolog编译器。