如何定义用户无法查询的规则? 我只希望程序本身通过另一个规则来调用这个规则。
例如:
规则1():-规则2()。
规则2():- 1<5.
?-规则1()。
真实
?-rule2()。
(我不知道答案是什么,我只是希望这个查询失败!)
使用 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/
首先,一些注意事项:
我认为你的意思是“谓词”而不是“规则”。谓词是一个
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)
查找源代码,这样如果他/她确实想要的话,仍然可以简单地查找正确的识别码。如果只是为了防止用户造成意外伤害,那么作为一种保护就足够了。
这让我想起了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.
在现代 Prolog 中,我们不再经常找到祖先/1 谓词。 但可以按照以下方式进行模拟。只需抛出一个错误,然后 如果错误带有堆栈跟踪,您将获得所需的一切:
ancestors(L) :- catch(sys_throw_error(ignore),error(ignore,L),true).
但要注意堆栈消除优化可能会减少堆栈,从而 祖先/1 返回的列表。
致以诚挚的问候
P.S.:堆栈消除优化已经在这里解释过: [4] 沃伦,D.H.D. (1983):抽象 Prolog 指令集,技术说明 309,SRI International,1983 年 10 月