使用 \==/2 或 diff/2 [英] Using \==/2 or dif/2

查看:57
本文介绍了使用 \==/2 或 diff/2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我想确保两个变量不会实例化为同一个术语,那么首选的方法是什么?

假设我需要在图中找到有向边,并且一个节点不能有自己的边:

node(a, x, y).节点(b,z,x).节点(c,y,y).

(这里的边是 a -> c, b -> a,但不是 c -> c)

以下工作:

edge(A, B) :- node(A, _, X), node(B, X, _), A \== B.

这也有效[swi-prolog]:

edge(A, B) :- dif(A, B), node(A, _, X), node(B, X, _).

这显然不起作用(因为 A 和 B 都还没有被实例化?):

edge(A, B) :- A \== B, node(A, _, X), node(B, X, _).

我想我的第一个解决方案的问题是,使用更复杂的 node 谓词,在 edge 失败之前可能会发生许多不必要的统一.另一方面,dif 位于一个库中,这表明它并不打算在如此简单的情况下使用(尽管它具有我似乎正在寻找的确切功能).

解决方案

仅出于优雅和教学的原因,dif/2 在这里和绝大多数其他情况下显然更可取,因为作为您已经注意到可能会发生很多不必要的统一",另外,还因为 dif/2 是一个纯粹且漂亮的声明性谓词,可以在所有方向和子句主体的任何位置使用与 (\==)/2 相反,不改变程序的含义.dif/2 也是 SWI-Prolog 中的自动加载谓词,这意味着您不需要显式导入任何库即可使用它,并且 dif/2 像任何内置谓词一样可用.

如果您使用 dif/2,您可以更轻松地推理您的代码.例如,在你的情况下,你开始:

<预>edge(A, B) :- node(A, _, X), node(B, X, _), dif(A, B).

然后,正如您所知 dif/2 是一个完全纯谓词,您知道您也可以将其写为:

<预>edge(A, B) :- dif(A, B), node(A, _, X), node(B, X, _).

此外,由于您知道 dif/2 总是会终止,因此您知道此更改最多可以改善程序的终止属性.

像所有的约束一样,dif/2 应该被使用.我强烈推荐它而不是不可交换的不纯谓词.

如果您担心性能,这里有一个小的比较,只需将 dif/2 与非声明性的 (\==)/2 比较两个谓词可以互换使用的用例:

<预>?- N = 1_000_000, 时间((((1,N,_),dif(a,b),false)).% 11,000,005 次推理,0.353 秒 内 0.352 CPU(100% CPU,31281029 唇)?- N = 1_000_000, 时间((((1,N,_),a\==b,false)).%@ % 3,000,001 次推理,在 0.107 秒内消耗 0.107 CPU(99% CPU,28167437 唇)

因此,使用 (\==)/2 有时会带来性能优势.但是,使用这种低级谓词也存在更严重的缺点:更难理解、更容易出错且不具有声明性.

因此我建议简单地使用 dif/2 来表示两个术语不同.

If I want to make sure that two variables do not instantiate to the same term, what is the preferred way to do it?

Let's say I need to find directed edges in a graph, and a node cannot have an edge to itself:

node(a, x, y). node(b, z, x). node(c, y, y).

(the edges here are a -> c, b -> a, but not c -> c)

The following works:

edge(A, B) :- node(A, _, X), node(B, X, _), A \== B.

This works too [swi-prolog]:

edge(A, B) :- dif(A, B), node(A, _, X), node(B, X, _).

This does not work, apparently (because neither A nor B are instantiated yet?):

edge(A, B) :- A \== B, node(A, _, X), node(B, X, _).

I guess my problem with the first solution is that, with a more complex node predicate, a lot of unnecessary unifications might take place before edge fails. The dif on the other hand is in a library, which suggests that it is not meant to be used in such a simple case (although it has the exact function that I seem to be looking for).

解决方案

For elegance and didactic reasons alone, dif/2 is clearly preferable here and also in the vast majority of other cases, since as you already note "a lot of unnecessary unifications might take place" otherwise, and also because dif/2 is a pure and nicely declarative predicate that can be used in all directions and at any place in the clause body without changing the meaning of the program, in contrast to (\==)/2. dif/2 is also an autoloaded predicate in SWI-Prolog, meaning that you need not import any library explicitly to use it, and dif/2 is available like any built-in predicate.

If you use dif/2 you can reason much more easily about your code. For example, in your case, you start with:

edge(A, B) :- node(A, _, X), node(B, X, _), dif(A, B).

and then, as you know that dif/2 is a completely pure predicate, you know that you can also write this as:

edge(A, B) :- dif(A, B), node(A, _, X), node(B, X, _).

Further, since you know that dif/2 always terminates, you know that this change can at most improve the termination properties of your program.

Like all constraints, dif/2 is meant to be used. I highly recommend it instead of impure predicates that are not commutative.

In case you are worried about performance, here is a small comparison, just comparing dif/2 against the non-declarative (\==)/2 in a use case where the two predicates can be used interchangeably:

?- N = 1_000_000, time((between(1,N,_),dif(a,b),false)).
% 11,000,005 inferences, 0.352 CPU in 0.353 seconds (100% CPU, 31281029 Lips)

?- N = 1_000_000, time((between(1,N,_),a\==b,false)).
%@ % 3,000,001 inferences, 0.107 CPU in 0.107 seconds (99% CPU, 28167437 Lips)

So, there are sometimes performance benefits when using (\==)/2. However, there are also much more severe drawbacks when using such a low-level predicate: It is harder to understand, more error-prone, and not declarative.

I therefore recommend to simply use dif/2 to express that two terms are different.

这篇关于使用 \==/2 或 diff/2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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