list - 元素在 Prolog 的列表中只出现一次

标签 list prolog predicate

我想编写一个谓词来检查元素是否在列表中恰好出现一次。

once(Element, List).

我的代码:
once(X, [H | T]) :-
    \+ X = H,
    once(X, T).
once(X, [X | T]) :-
    \+ member(X, T).

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

?- once(b, [b,a,a,c,b,a]).
false.

但如果我问:
once(X, [b,a,a,c,b,a]).

序言回答:
false

为什么? Prolog 应该找到 X = c 解决方案。错误在哪里?

最佳答案

运行 trace in prolog 对确定这类问题的答案非常有帮助。我们将在此处手动进行跟踪以进行说明。

让我们看看你的谓词:

once(X, [H | T]) :-
    \+ X = H,
    once(X, T).
once(X, [X | T]) :-
    \+ member(X, T).

现在让我们考虑一下查询:
once(X, [b,a,a,c,b,a]).

首先,Prolog 尝试谓词的第一个子句。头像是once(X, [H|T])第一个表达式是 \+ X = H ,这将变为:
once(X, [b|[a,a,c,b,a]]) :-  % [H|T] instantiated with [b,a,a,c,b,a] here
                             %   So, H is b, and T is [a,a,c,b,a]
    \+ X = b,
    ...
X用原子 b 实例化(统一)在这里,统一的结果成功了。但是,前面有一个否定,所以 \+ X = b 的结果, 当 X最初是未绑定(bind)的,自 X = b 起为假统一 Xb并且是真的。

因此,第一个子句失败了。 Prolog 移至下一个子句。子句标题是 once(X, [X|T])以下是\+ member(X, T) ,变成:
once(b, [b|[a,a,c,b,a]]) :-    % X was instantiated with 'b' here,
                               %   and T instantiated with [a,a,c,b,a]
    \+ member(b, [a,a,c,b,a]).
member(b, [a,a,c,b,a])成功是因为 b[a,a,c,b,a] 的成员.因此,\+ member(b, [a,a,c,b,a])失败。

第二个条款也失败了。

谓词 once(X, [b,a,a,c,b,a]) 没有更多子句.他们都失败了。所以查询失败。主要问题是 \+ X = H (甚至 X \= H ,当 X 未实例化时,不会从列表中选择与 H 中实例化的值不同的值。它的行为在逻辑上不是你想要的。

更直接的谓词方法是:
once(X, L) :-           % X occurs once in L if...
    select(X, L, R),    % I can remove X from L giving R, and
    \+ member(X, R).    % X is not a member of R
select将根据需要查询未实例化的 X ,所以这将产生:
?- once(c, [b,a,a,c,b,a]).
true ;
false.

?-  once(b, [b,a,a,c,b,a]).
false.

?- once(X, [b,a,a,c,b,a]).
X = c ;
false.

顺便说一句,我会避免使用谓词名称 once因为它是 Prolog 中内置谓词的名称。但它与这个特定问题无关。

关于list - 元素在 Prolog 的列表中只出现一次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22746523/

相关文章:

Python列表: Pythonic way to get unique items in given List from a given Set

java - 将 vector 转换为列表

prolog - 遍历上下文无关语法

prolog - 访问 prolog 中的程序列表

parsing - 使用 prolog 构建解析树

xml - Xpath 使用谓词在数据中匹配带有斜线的节点

javascript - 如何在 Javascript 中编写 Array.prototype.every() 方法

python - 当其他两列的元组唯一时,Pandas 添加新列并用列表中的项目填充它

lisp - 普通口齿不清 : making rules about input values

php 列表到表中