定义用户无法查询的规则

时间:2011-02-25 00:48:16

标签: prolog logtalk

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

例如:

rule1(): - rule2()。

rule2(): - 1< 5。

- ?规则1()

- ?规则2()

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

3 个答案:

答案 0 :(得分:6)

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

一个简单的例子:

:- 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/

的更多信息和大量示例

答案 1 :(得分:2)

首先,一些注意事项:

  • 我认为你的意思是&#34;谓词&#34;而不是&#34;规则&#34;。谓词是name/k,例如help/0(而help/1是另一个),并且可以有多个子句,其中包括事实和规则,例如length([], 0).(事实)和length([H|T], L) :- ... .(规则)是一个谓词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,以便Prolog在错误消息之后打印false而不是true。最后,我不知道如何阻止用户使用listing(predicate2)查找源代码,这样如果他/她真的想要,它仍然可以简单地查找正确的识别码。如果仅仅是为了防止用户意外受到伤害,它应该足以作为保护。

答案 2 :(得分:2)

这让我想起了Java中的设施。有人可以查询 curent call stack,并使用它来调节调用权限 一个方法。翻译成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.

在现代Prolog中,我们不再经常发现祖先/ 1谓词。 但它可以按以下方式进行模拟。只是抛出错误,然后 如果错误装饰有堆栈跟踪,您将获得所需:

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

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

最好的问候

P.S。:此处已经解释了堆栈消除优化: [4] Warren,D.H.D。 (1983):抽象Prolog指令集,技术说明309,SRI国际,1983年10月

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