`memberd/2` 的更多确定性? [英] More determinism for `memberd/2`?

查看:23
本文介绍了`memberd/2` 的更多确定性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

许多系统都提供了 member/2 的纯粹而高效的实现.特别是,没有选择点可供选择:

Many systems provide a pure and efficient implementation of member/2. In particular, no choice point is left open for:

?- member(b,[a,b]).
true.

然而,member/2 的幼稚实现会产生:

whereas, a naive implementation of member/2 produces rather:

?- member(b,[a,b]).
true ;
false.

从声明的角度来看,这当然是正确的,但效率较低.

which is certainly correct from a declarative viewpoint, but less efficient.

另一方面,member/2 存在一些技术问题.它允许冗余解决方案,例如:

On the other hand, there are some technical problems with member/2. It permits redundant solutions, like in:

?- member(a,[a,a]).
true ;
true.

memberd/2 使用 if_/3(=)/3.

memberd(E, [X|Xs]) :-
   if_(E = X, true, memberd(E, Xs)).

?- memberd(a,[a,a]).
true.

不幸的是,这个定义让选择点再次打开 - 产生 ;false(剩余的选择点")在成员没有的情况下:

Unfortunately, this definition leaves choice points open again - producing ; false ("leftover choicepoints") in situations where member does not:

?- memberd(X,[a,b]).
X = a ;
X = b ;
false.    % BAD - to be avoided!

?- member(X,[a,b]).
X = a ;
X = b.

所以我的问题是:memberd/2 的定义是否可以避免上述选择点?

So my question: Is there a definition of memberd/2 that avoids the choice point as this one above?

推荐答案

首先,为了清楚起见,我们将 memberd 重命名为 memberd_old.

First, we rename memberd to memberd_old for the sake of clarity.

然后,我们实现 memberd_new/2,它使用滞后和第一个参数索引来防止在列表末尾创建无用的选择点.

Then, we implement memberd_new/2, which uses lagging and 1st argument indexing to prevent the creation of the useless choicepoint at the end of the list.

memberd_new(E,[X|Xs]) :-
   memberd_new_aux(Xs,X,E).

% auxiliary predicate to enable first argument indexing
memberd_new_aux([],E,E).
memberd_new_aux([X1|Xs],X0,E) :-
   if_(E=X0, true, memberd_new_aux(Xs,X1,E)).

让我们比较一下 member/2(SWI-Prolog 内置谓词)、memberd_old/2memberd_new/2

Let's compare member/2 (SWI-Prolog builtin predicate), memberd_old/2, and memberd_new/2!

首先,地面查询:

?- member(a,[a,a]).
true ;
true.                       % BAD!

?- memberd_old(a,[a,a]).
true.

?- memberd_new(a,[a,a]).
true.

接下来,另一个地面查询:

Next, another ground query:

?- member(a,[a,b]).
true ;                      % BAD!
false.

?- memberd_old(a,[a,b]).
true.

?- memberd_new(a,[a,b]).
true.

现在,一个查询有多个不同的解决方案:

Now, a query having multiple distinct solutions:

?- member(X,[a,b]).
X = a ;
X = b.

?- memberd_old(X,[a,b]).
X = a ;
X = b ;                     % BAD!
false.

?- memberd_new(X,[a,b]).
X = a ;
X = b.

编辑

这里介绍的 memberd_new/2 的实现已被弃用.

我建议使用此答案中显示的较新实现.

I recommend using the newer implementation shown in this answer.

这篇关于`memberd/2` 的更多确定性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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