如何定义用户无法查询的规则? 我只希望程序本身通过另一条规则调用此规则。
例如:
rule1(): - rule2()。
rule2(): - 1< 5。
- ?规则1()
真
- ?规则2()
(我不知道答案是什么,我只是希望这个查询失败!)
答案 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)
的更多信息和大量示例
答案 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