Prolog:规则的头部只有匿名变量,没有正文 [英] Prolog: Rules with nothing but anonymous variables in the head, and no body

查看:56
本文介绍了Prolog:规则的头部只有匿名变量,没有正文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆