首页 > 解决方案 > X 在诸如“example([X|L1], [X,X|L2])”之类的谓词的第二个操作数中计算为什么

问题描述

我正在尝试解决列表的每个元素都重复的问题,解决方案如下:

duplicate([],[]).
duplicate([X|Xs],[X,X|Ys]) :-
   duplicate(Xs,Ys).

我知道 Prolog 将 X 与 X 列表的第一个元素统一起来,但是如果它已经与第一个列表统一,它与第二个操作数/列表统一/做什么呢?

标签: prolog

解决方案


我将尝试解释这个谓词是如何工作的,因为我认为你对 Prolog 将要做什么的期望有些不对劲,我不完全确定它是什么。通常,Prolog 的新用户期望谓词的最终参数在某种程度上是特殊的,在具有表达式评估语义的传统语言中模拟返回值。你的措辞让我觉得你可能认为 Prolog 有一些程序性导致它从左到右处理参数。这些都不是真的。这里真正重要的是当 Prolog 去证明一个目标时实例化的内容。

了解 Prolog 如何推理此目标的最迟钝但可能最具体的方法是使用两个变量调用它并查看返回的结果:

?- duplicate(X,Y).
X = Y, Y = [] ;

X = [_8100],
Y = [_8100, _8100] ;

X = [_8100, _8118],
Y = [_8100, _8100, _8118, _8118] ;

X = [_8100, _8118, _8136],
Y = [_8100, _8100, _8118, _8118, _8136, _8136] .

你可以继续寻求答案,但现在你可能明白了。值得注意的是,Prolog 生成了两个列表,一个包含唯一变量列表,另一个包含重复的相同变量。它在不知道这些变量实际上是什么的情况下设法做到这一点。更直接地说,这些都是 Prolog 可以做的统一的例子:

?- X = [Y1,Y2|Ys].
X = [Y1, Y2|Ys].

?- [Y1,Y2|Ys] = X.
X = [Y1, Y2|Ys].

这里没有任何方向性,Prolog 可以毫无问题地剥离一些结构。您也可以事后绑定这些变量:

?- [Y1,Y2|Ys] = X, Y2 = foo, Ys = [].
Y2 = foo,
Ys = [],
X = [Y1, foo].

因此,多次执行涉及相同变量的操作实际上根本不是问题:

?- L1 = [X|Xs], L2 = [X,X|Ys].
L1 = [X|Xs],
L2 = [X, X|Ys].

?- L1 = [X|Xs], L2 = [X,X|Ys], X = foo.
L1 = [foo|Xs],
X = foo,
L2 = [foo, foo|Ys].

?- L2 = [X,X|Ys], L1 = [X|Xs], L1 = [1,2,3,4].
L2 = [1, 1|Ys],
X = 1,
L1 = [1, 2, 3, 4],
Xs = [2, 3, 4].

我没有看到任何令人惊讶的地方,但我也没有看到任何令人惊讶的地方duplicate/2。你有没有发现任何令人惊讶的地方?如果是这样,那可能会帮助我缩小误解。

此外,看到其他实例化模式不应该但可能会让您感到惊讶:

?- duplicate(A, [1,1,2,2,3,3]).
A = [1, 2, 3].

这是从其他人那里得到的,但如果它看起来很荒谬,那么我们仍然需要弄清楚误解在哪里。


推荐阅读