Prolog membership predicate

混江龙づ霸主 提交于 2020-05-23 21:07:26

问题


I need to write a Prolog predicate that avoids redundant answers with items occurring multiple times in the list at hand, as shown in the following sample queries:

?- member(a, [a, b, a]).
true
?- member(X, [a, b, a]).
X = a ;
X = b ;
false.
?- member(X, [a, b, a, c, a, d, b]).
X = a ;
X = b ;
X = c ;
X = d ;
false.

I know that the following would output all of them regardless of the repeats:

member(X, [X|_]).
member(X, [_|T]) :- member(X, T).

回答1:


Compare both clauses, are there cases, where both apply?

member(X, [X|_T]).
member(X, [_Y| T]) :- member(X, T).

Just compare both clauses' heads to each other. Or, let Prolog do it for you:

?- member(X, [X|_T]) = member(X, [_Y| T]).
   X = _Y, _T = T.

So the _Y and X must be the same. When are they the same? Always, if the first clause is true! So we need to exclude that case by adding a further condition that in the second clause, they must be different.

memberd(X, [X|_T]).
memberd(X, [Y| T]) :- dif(X,Y), memberd(X, T).
?- member(X, [a, b, a, c, a, d, b]).
   X = a
;  X = b
;  X = a
;  X = c
;  X = a
;  X = d
;  X = b
;  false.
?- memberd(X, [a, b, a, c, a, d, b]).
   X = a
;  X = b
;  X = c
;  X = d
;  false.
?- memberd(a, [a, b, a, c, a, d, b]).
   true
;  false.

The last query can be improved using library(reif) which I use in Scryer, but which is also available for SICStus|SWI:

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

?- memberd(a, [a, b, a, c, a, d, b]).
   true.


来源:https://stackoverflow.com/questions/61133211/prolog-membership-predicate

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!