Prolog:规则的头部只有匿名变量,没有正文 [英] Prolog: Rules with nothing but anonymous variables in the head, and no body
问题描述
Prolog 的语法使用 :-
规则格式:
tree(G) :- acyclic(G) , connected(G).
,将 G 的状态表示为一棵树取决于状态为非循环和连通的.
这种语法可以隐式地扩展到事实.遵循相同的示例:
connected(graphA)
建议 connected(graphA):-true.
从这个意义上说,人们可以将 Prolog 事实松散地定义为始终为真的 Prolog 规则.
我的问题:在任何情况下,没有实体的规则(假定在所有条件下都为真)是否合适?从语法上讲,这样的规则如下所示.
graph(X).
(建议 graph(X):-true.
)
在回答之前,重新表述您的问题:
<块引用>在 Prolog 中,你会写一个规则,头部只有匿名变量,没有正文吗?
术语在这里很重要.事实只是规则,只有一个头而没有体(这就是为什么你的问题有点混乱).匿名变量是您在谓词子句的上下文中明确告诉编译器要忽略的变量(谓词子句是变量的句法范围).如果您确实尝试将此谓词子句提供给 Prolog 编译器:
foo(Bar).
您将收到单例变量"警告.相反,你可以写
foo(_).
这告诉编译器这个参数是故意忽略的,不应该尝试使用它进行变量绑定.
在操作上,当 Prolog 试图证明规则时会发生什么?
- 首先,统一规则头部的所有参数,这可能会导致新的变量绑定;
- 然后,它尝试使用所有现有的变量绑定来证明规则的主体.
如您所见,第二步使其成为递归定义的算法:证明规则的主体意味着证明其中的每条规则.
回到你的问题:这个操作的意义是什么:
foo(_).
<块引用>
有一个谓词foo/1
,它对任何参数都是真的,因为在头部没有变量绑定要完成,而且总是如此,因为不需要证明子目标.
我至少见过这样一条规则的一种用法:查看 SWI-Prolog 手册的这一部分.小代码示例如下:
term_expansion(my_class(_), Clauses) :-findall(my_class(C),string_code(_, "~!@#$", C),条款).我的课(_).
您应该阅读链接的文档以了解这样做的动机.代码本身的目的是在编译时向 Prolog 数据库添加一个事实表.这是通过术语扩展完成的,这是一种代码转换机制,通常通过 <使用代码>term_expansion/2.您需要 my_class/1
的定义,以便 term_expansion/2
可以将其提取、转换并替换为扩展代码.我强烈建议你把上面剪下来的,放在一个文件里,查阅它并使用listing/1
看看效果如何.我得到:
?- 列表(my_class).我的类(126).my_class(33).my_class(64).my_class(35).my_class(36).真的.
注意:在本例中,您可以用任何内容替换出现的两次 my_class(_)
.你也可以这么写:
term_expansion(foobar, Clauses) :-findall(my_class(C),string_code(_, "~!@#$", C),条款).食品吧.
最终结果是一样的,因为操作意义是一样的.但是,使用 my_class(_)
是自文档化的,并且使代码的意图更加明显,至少对于作为 SWI-Prolog 的作者的经验丰富的 Prolog 开发人员来说是这样;)
Prolog's grammar uses a <head> :- <body>
format for rules as such:
tree(G) :- acyclic(G) , connected(G).
, denoting status of G as a tree depends on status as acyclic and connected.
This grammar can be extended in an implicit fashion to facts. Following the same example:
connected(graphA)
suggests connected(graphA):-true.
In this sense, one might loosely define Prolog facts as Prolog rules that are always true.
My question: Is in any context a bodiless rule (one that is presumed to be true under all conditions) ever appropriate? Syntactically such a rule would look as follows.
graph(X).
(suggesting graph(X):-true.
)
Before answering, to rephrase your question:
In Prolog, would you ever write a rule with nothing but anonymous variables in the head, and no body?
The terminology is kind of important here. Facts are simply rules that have only a head and no body (which is why your question is a bit confusing). Anonymous variables are variables that you explicitly tell the compiler to ignore in the context of a predicate clause (a predicate clause is the syntactical scope of a variable). If you did try to give this predicate clause to the Prolog compiler:
foo(Bar).
you will get a "singleton variable" warning. Instead, you can write
foo(_).
and this tells the compiler that this argument is ignored on purpose, and no variable binding should be attempted with it.
Operationally, what happens when Prolog tries to prove a rule?
- First, unification of all arguments in the head of the rule, which might lead to new variable bindings;
- Then, it tries to prove the body of the rule using all existing variable bindings.
As you can see, the second step makes this a recursively defined algorithm: proving the body of a rule means proving each rule in it.
To come to your question: what is the operational meaning of this:
foo(_).
There is a predicate
foo/1
, and it is true for any argument, because there are no variable bindings to be done in the head, and always, because no subgoals need to be proven.
I have seen at least one use of such a rule: look at the very bottom of this section of the SWI-Prolog manual. The small code example goes like this:
term_expansion(my_class(_), Clauses) :-
findall(my_class(C),
string_code(_, "~!@#$", C),
Clauses).
my_class(_).
You should read the linked documentation to see the motivation for doing this. The purpose of the code itself is to add at compile time a table of facts to the Prolog database. This is done by term expansion, a mechanism for code transformations, usually used through term_expansion/2
. You need the definition of my_class/1
so that term_expansion/2
can pick it up, transform it, and replace it with the expanded code. I strongly suggest you take the snipped above, put it in a file, consult it and use listing/1
to see what is the effect. I get:
?- listing(my_class).
my_class(126).
my_class(33).
my_class(64).
my_class(35).
my_class(36).
true.
NB: In this example, you could replace the two occurrences of my_class(_)
with anything. You could have just as well written:
term_expansion(foobar, Clauses) :-
findall(my_class(C),
string_code(_, "~!@#$", C),
Clauses).
foobar.
The end result is identical, because the operational meaning is identical. However, using my_class(_)
is self-documenting, and makes the intention of the code more obvious, at least to an experienced Prolog developer as the author of SWI-Prolog ;).
这篇关于Prolog:规则的头部只有匿名变量,没有正文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!