0

如何定义用户无法查询的规则?我只希望程序本身通过另一个规则调用这个规则。

前任:

规则 1():- 规则 2()。

规则 2():- 1<5。

?-规则1()。

真的

?-rule2()。

(我不知道答案会是什么,我只是希望这个查询失败!)

4

3 回答 3

5

使用 Logtalk 对象来封装您的谓词。只能调用您声明为 public 的谓词(从对象外部)。Prolog 模块不会阻止调用任何谓词,因为使用显式限定会绕过显式导出的谓词列表。

一个简单的例子:

:- object(rules).

    :- public(rule1/1).
    rule1(X) :-
        rule2(X).

    rule2(X) :-
        X < 5.

:- end_object.

编译并加载上述对象后:

?- rules::rule1(3).
true.

?- rules::rule2(3).
error(existence_error(predicate_declaration,rule2(3)),rules::rule2(3),user)

如果您编辑目标代码并将 rule2/1 显式声明为私有,您将得到错误:

?- rules::rule2(3).
error(permission_error(access,private_predicate,rule2(3)),rules::rule2(3),user)

更多信息和大量示例,请访问http://logtalk.org/

于 2011-02-25T17:55:09.520 回答
2

首先,一些注意事项:

  • 我认为您的意思是“谓词”而不是“规则”。谓词是name/k诸如help/0(and help/1is another)之类的事物,可以有多个子句,其中包括事实和规则,例如length([], 0).(a fact)和length([H|T], L) :- ... .(a rule)是一个谓词的两个子句length/2

  • 不要对没有参数的谓词使用空括号——至少在 SWI-Prolog 中,这根本不起作用。只是在所有地方使用predicate2而不是。predicate2()

  • 如果你试图调用一个未定义的谓词,SWI-Prolog 会说
    ERROR: toplevel: Undefined procedure: predicate2/0 (DWIM could not correct goal),而 Sicstus-Prolog 会说
    {EXISTENCE ERROR: predicate2: procedure user:predicate2/0 does not exist}

现在,来回答。我想到了两个想法。

(1) 这是一个 hack,但是您可以在每次需要谓词时断言谓词并在之后立即收回它们:

predicate1 :- 
      assert(predicate2), predicate2, retractall(predicate2).

如果您想要 的主体和参数predicate2,请执行assert(predicate2(argument1, argument2) :- (clause1, clause2, clause3)).

(2) 实现此目的的另一种方法是为您不希望用户调用的谓词引入一个额外参数,并将其用于用户无法提供但您可以通过调用提供的标识谓词。这可能是一个看起来很随机的大常数,甚至是一个句子。这甚至使您能够在提供错误标识的情况下输出自定义错误消息。

例子:

 predicate1 :- 
        predicate2("Identification: 2349860293587").

 predicate2(Identification) :- 
        Identification = "Identification: 2349860293587", 
        1 < 5.
 predicate2(Identification) :- Identification \= "Identification: 2349860293587",
        write("Error: this procedure cannot be called by the user. Use predicate1/0 instead."), 
        fail.

我没有predicate2("Identification: 2349860293587")对 的第一个子句使用等效项predicate2/0,因为我不确定子句的头部可能出现在 Prolog 消息中的哪个位置,而您不希望这样。我fail在第二个子句的末尾使用 a 只是为了让 Prolog 打印false而不是true在错误消息之后打印。最后,我不知道如何阻止用户查找源代码,listing(predicate2)这样如果他/她真的想要,仍然可以简单地查找正确的识别码。如果只是为了防止用户造成意外伤害,那么它应该足以作为一种保护。

于 2011-02-25T18:03:34.817 回答
1

这让我想起了在 Java 中找到的设施。可以查询当前调用堆栈,并以此来调节调用方法的权限。翻译成 Prolog,我们在旧的 DEC-10 Prolog 中发现以下谓词:

祖先(L)
将 L 与当前子句的祖先目标列表统一起来。该列表以父目标开始,以来自编译子句中的调用的最新祖先结束。该列表使用 print 打印,每个条目前面是括号中的调用编号,后跟深度编号(如跟踪消息中给出的那样)。如果调用没有数字(如果在进一步执行之前未打开调试模式,则会发生这种情况),则用“-”标记。不适用于已编译的代码。

由于顶层通常是一个已编译的谓词 prolog/0,这可以用来编写一个谓词来检查它自己的调用堆栈,然后决定它是否要投入使用。

rule2 :- ancestors(L), length(L,N), N<2, !, write('Don't call me'), fail.
rule2 :- 1<5.

在现代 Prologs 中,我们不再经常发现祖先/1 谓词。但它可以按照以下方式进行模拟。只需抛出一个错误,如果错误带有堆栈跟踪,您将获得所需的一切:

ancestors(L) :- catch(sys_throw_error(ignore),error(ignore,L),true).

但要注意堆栈消除优化可能会减少堆栈,从而减少祖先/1 返回的列表。

此致

PS:堆栈消除优化已在此处解释:[4] Warren, DHD (1983): An Abstract Prolog Instruction Set, Technical Note 309, SRI International, October, 1983

Jekejeke Prolog 的讨论可以在这里找到:http: //www.jekejeke.ch/idatab/doclet/prod/en/docs/10_pro08/13_press/03_bench/05_optimizations/03_stack.html

于 2011-02-26T17:08:38.547 回答