memberchk / 2的声明性用法

时间:2015-10-25 10:43:34

标签: prolog logical-purity

memberchk/2是一个常用的谓词,用member/2来定义,如下所示:

memberchk(X, Xs) :-
   once(member(X, Xs)).

因此,只有member/2的第一个答案才能成功。它的完整程序意义不适合纯粹的关系。作为其非关系行为的一个例子,考虑

?- memberchk(b, [X,b]), X = a.
false.

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

另一方面,在许多情况下memberchk/2将使用充分实例化的参数调用,其中它可以被视为纯关系的有效近似。

背后的一个纯粹的关系是memberd/2(使用if_/3):

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

对于充分实例化的案例,是否还有memberchk/2可以近似的其他纯关系?

换句话说:memberd/2memberchk/2的完整声明替换,还是memberchk/2无法替换memberd/2的合法案例?

3 个答案:

答案 0 :(得分:4)

以下是member/2的一个众所周知的示例用法,memberd/2无法用bridge.pl表示Pascal Van Hentenryck给出的桥接调度问题。

在设置阶段使用member/2

setup(K,Ende,Disj):-
    jobs(L),
    make_vars(L,K),
    member([stop,_,Ende],K),
    ....

所以在这里,有效地使用三元素列表中的第一个元素来选择特定任务,而memberd/2使用整个元素进行比较。结果,这个setup/3留下了许多选择点(实际上,219)。有些人(如SICStus)在这种情况下使用memberchk/2,从而冒着非单调性的风险。

使用以下纯替换,可以避免所有选择点。

member3l([N,D,A], Plan) :-
   tmember(l3_t(N,D,A),  Plan).

l3_t(N,D,A, X, T) :-
   X = [Ni|_],
   if_(N = Ni, ( X=[N,D,A], T = true ), T = false ).

tmember(P_2, [X|Xs]) :-
   if_( call(P_2, X), true, tmember(P_2, Xs) ).

或者使用library(lambda)

member3li([N,Nd,Na], Plan) :-
   tmember([N,Nd,Na]+\X^T^
       (  X=[Nk|_],
          if_( Nk = N, ( X=[N,Nd,Na], T = true ), T = false ) ),
      Plan).

tmember/2的其他用途:

old_member(X, Xs) :-
   tmember( X+\E^T^( X = E, T = true ; T = false ), Xs).

old_memberd(X, Xs) :-
   tmember(=(X), Xs).

这是一个更紧凑的表示:

member3l([N,D,A], Plan) :-
   tmember({N,D,A}+\[Ni,Di,Ai]^cond_t(N = Ni, [D,A] = [Di,Ai] ), Plan).

使用library(lambda)cond_t/3

cond_t(If_1, Then_0, T) :-
   if_(If_1, ( Then_0, T = true ), T = false ).

答案 1 :(得分:2)

memberb / 2是建设性否定的典型例子。您可以将要求颠倒过来,例如需要:

?- ~ member(X, [a,b,c]).
dif(X, a),
dif(X, b),
dif(X, c)

哪里〜将是建设性的否定。关于建构性否定如何与if_相关的讨论,例如here

对于成员/ 2或某些人来说,完全声明性归纳定义的缺点是Prolog分离(;)/ 2不能简化 约束,并且Prolog没有一个也可以简化diff / 2等约束的概念。

因此,当您使用有限的(;)/ 2和missig forall正确地执行此操作时,您可以获得最佳案例完整解决方案,当您查看完整解决方案时,该解决方案包含许多冗余约束会产生。

以下是Jekejeke Prolog中的一个示例,它要求谓词diff / 2的Minlog扩展名可用:

:- use_module(library(term/diff)).
:- use_module(library(basic/lists)).
test(Y) :- diff(X, a), member(Y, [a,X]).

?- test(X).
X = a ;
diff([X], [a])

以上两个答案基本上都是X = a~(X = a),其中大多数逻辑与单个答案true相同。

你需要一个Prolog解释器,在某些点工作集面向。也许一些运营商会强制进行面向集合的处理。但它可能会破坏传统的Prolog代码。您可能不仅可以将完全声明性定义隐藏在基于不那么声明性定义的代码中。

再见

答案 2 :(得分:2)

以下答案与memberchk/2的原始问题没有直接关系;相反,它是定义this previous answer tmember/2的后续行动。

我们建议像这样概括成语tmember/2

t_non_empty_suffix(P_3, [X|Xs]) :-
   if_(call(P_3,Xs,X), true, t_non_empty_suffix(P_3,Xs)).

t_non_empty_suffix/2Prolog lambdas的基础上,我们可以像这样定义tmemberX/2

:- use_module(library(lambda)).

tmemberX(P_2, Xs) :-
   t_non_empty_suffix(P_2+\_^call(P_2), Xs).

以下old_memberX/2old_memberdX/2使用tmemberX/2代替tmember/2

old_memberX(X, Xs) :-
   tmemberX(X+\E^T^( X = E, T = true ; T = false ), Xs).

old_memberdX(X, Xs) :-
   tmemberX(=(X), Xs).

让我们将old_member/2old_memberX/2 ...

进行比较
?- old_member(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 2 ; X = 3 ; X = 4 ; X = 3 ; X = 4 ; X = 5 ; false.

?- old_memberX(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 2 ; X = 3 ; X = 4 ; X = 3 ; X = 4 ; X = 5 ; false.

...和old_memberd/2old_memberdX/2

?- old_memberd(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 4 ; X = 5 ; false.

?- old_memberdX(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 4 ; X = 5 ; false.

确定!如何直接根据old_member定义old_memberd / t_non_empty_suffix/2

old_memberSFX(X, Xs) :-
   t_non_empty_suffix(X+\_^E^T^( X = E, T = true ; T = false ), Xs).

old_memberdSFX(X, Xs) :-
   t_non_empty_suffix(X+\_^E^( X = E ), Xs).

使用这些谓词运行上面的查询:

?- old_memberSFX(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 2 ; X = 3 ; X = 4 ; X = 3 ; X = 4 ; X = 5 ; false.

?- old_memberdSFX(X, [1,2,3,2,3,4,3,4,5]).
X = 1 ; X = 2 ; X = 3 ; X = 4 ; X = 5 ; false.

好吧!与之前的结果相同。

让我们深入挖掘一下!作为t_non_empty_suffix/2的展示位置,请考虑duplicate_in/2
使用t_non_empty_suffix/2Prolog lambdas(=)/3memberd_t/3我们定义:

','(P_1, Q_1, T) :-
   if_(P_1, call(Q_1,T), T = false).

duplicate_in(X, Xs) :-
   t_non_empty_suffix(X+\Es^E^( X = E, memberd_t(E, Es) ), Xs).

示例查询:

?- duplicate_in(X, [1,2,3,2,3,4,3,4,5]).
  X = 2         % [1,2,3,2,3,4,3,4,5]    (2 occurs  twice)
; X = 3         % [1,2,3,2,3,4,3,4,5]    (3 occurs thrice)
; X = 4         % [1,2,3,2,3,4,3,4,5]    (4 occurs  twice)
; false.