【问题标题】:How to use predicate sharing the same name from several modules in Prolog如何使用 Prolog 中多个模块的同名谓词
【发布时间】:2018-06-19 21:21:21
【问题描述】:

我是 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,因为我将动态添加/删除数据库文件。

提前感谢您的任何建议!

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

【问题讨论】:

  • 那么这些谓词是不同的?我敢肯定这在您的脑海中是有道理的,但这在 Prolog 中确实不是一个好的设计。有意义的是将一个谓词分布在多个文件中,这样应该可以正常工作。
  • 感谢您的回答。如果我只使用一个数据库文件或几个没有模块的文件,就没有你说的问题。问题是为了能够选择我想在哪个数据库文件中“断言”我的新事实,我必须将每个数据库放在单独的模块中。使用持久性库,我必须定义哪些谓词将被动态添加(通过 persistent/1),麻烦就来了。
  • 如果您必须分别调用位于不同模块中的谓词,也许它们不应该具有相同的名称?也许它们应该被称为db1_predicate1 等。或者数据库名称是谓词的一个参数并且谓词确实具有相同的名称。在这里很难说清楚,因为您的用例没有详细说明。
  • 我必须从不同的模块调用我的谓词,因为持久性库的工作方式,而不是因为我自己的需要。在每个模块中更改谓词名称是一种可能性,但我必须在我的第三个文件“predicates.pl”中反映它。由于我将动态创建新数据库,因此我还必须使“predicates.pl”持久化并相应地更新它。我检查了文档,但持久性似乎只适用于事实而不适用于谓词定义。 (但我可能错了)
  • 如果您认为事实与谓词不同,我不确定我是否遵循“持久性”的含义。在 Prolog 中,谓词只是数据库中的一个术语,就像事实一样。碰巧它是某种可查询形式的事实::-( head, body )

标签: prolog swi-prolog


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    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) :- predicate1(A,B), predicate2(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 的 message to self 控制结构。这意味着在一个目标中,例如:

    ?- 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 编译器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多