实现一个 Prolog 谓词,说明一个元素是否属于一个列表。非数字列表的问题

And*_*ili 5 prolog prolog-dif

我正在为大学考试学习 Prolog,但我在这个练习中遇到了问题:

not_member(X,L)如果元素X不属于列表,则实现为 TRUE的谓词L

如果我的推理是正确的,我已经找到了解决方案:

% FACT (BASE CASE): It is TRUE that X is not in the list if the list is empty.
not_member(_,[]).

% RULE (GENERAL CASE): If the list is non-empty, I can divide it in its Head
%   element and the sublist Tail. X does not belong to the list if it is different 
%   from the current Head element and if it does not belong to the sublist Tail.
not_member(X,[Head|Tail]) :-
   X =\= Head,
   not_member(X,Tail).
Run Code Online (Sandbox Code Playgroud)

此代码适用于数字列表,如以下查询所示:

2 ?- not_member(4, [1,2,3]).
true.

3 ?- not_member(1, [1,2,3]).
false.
Run Code Online (Sandbox Code Playgroud)

但是,对于包含一些非数字元素的列表,它不起作用并报告错误:

4 ?- not_member(a, [a,b,c]).
ERROR: =\=/2: Arithmetic: `a/0' is not a function
Run Code Online (Sandbox Code Playgroud)

为什么?

Hai*_*ile 7

让我们检查文档!

(=\=)/2是算术运算符。

+Expr1 =\= +Expr2 如果表达式 Expr1 的计算结果不等于 Expr2,则为真。

您必须使用(\=)/2来比较两个通用术语:

not_member(_, []) :- !.

not_member(X, [Head|Tail]) :-
     X \= Head,
    not_member(X, Tail).
Run Code Online (Sandbox Code Playgroud)

和:

?- not_member(d, [a,b,c]).
true.
Run Code Online (Sandbox Code Playgroud)

  • (不是详细解释)这是一个切入点。它可以防止回溯,但这不是强制性的。在这种情况下,可以使用它,因为一旦统一在 not_member(_, []) 上成功。我们不需要检查其他“解决方案”,因此我们“剪切”prolog 搜索树并停止计算。 (3认同)

rep*_*eat 5

使用获得符合逻辑的答案——适用地面非地面情况!

就像在这个答案中一样,我们定义non_member(E,Xs)maplist(dif(E),Xs)

让我们把maplist(dif(E),Xs)not_member(E,Xs) 通过@Haile到测试!

?- not_member (E,[1,2,3])。
假的。%错了!“E=4”呢?

?- maplist(dif(E),[1,2,3])。
差异(E,1),差异(E,2),差异(E,3)。未决目标的成功百分比

是否坚定?(有关此重要问题的更多信息,请阅读 答案。)

?- E=d, not_member (E,[a,b,c])。
E = d。
?-       not_member (E,[a,b,c]), E=d。
假的。%不坚定

?- E=d, maplist(dif(E),[a,b,c])。
E = d。
?- maplist(dif(E),[a,b,c]), E=d。% 坚定
E = d。

让我们不要忘记最一般的用途!

?- not_member (E,Xs)。               
Xs = []。%一很多解决方案是失踪了!

?- maplist(dif(E),Xs)。
  Xs = []
; Xs = [_A] , dif(E,_A)
; Xs = [_A,_B] , dif(E,_A), dif(E,_B)
; Xs = [_A,_B,_C], dif(E,_A), dif(E,_B), dif(E,_C)
...