我正在Learn Prolog Now进行此练习:
练习4.4
写一个谓词swap12(List1,List2)来检查List1是否是 与List2相同,只是交换了前两个元素。
这是我到目前为止所做的:
swap12([],[]).
swap12([a, b | Ta], [b, a | Tb]) :- swap12(Ta, Tb).
但是当我尝试评估这个时,我得到以下结果:
?- swap12(X, Y).
X = Y, Y = [] ;
X = [a, b],
Y = [b, a] ;
X = [a, b, a, b],
Y = [b, a, b, a] .
我做错了什么?
目标是拥有以下内容:
swap12(X,Y).
X = [a, b].
Y = [b, a].
X = [a, b, b].
Y = [b, a, a].
等。请帮忙!
答案 0 :(得分:1)
第一句:
swap12([],[]).
说交换空列表的前两个元素是空列表。我想,也许,根据定义,人们可能会这样说。但由于空列表没有元素,因此可能不会被认为是真的。
你的第二个条款是:
swap12([a, b | Ta], [b, a | Tb]) :- swap12(Ta, Tb).
如果您交换[a, b | Ta]
的前两个元素,那么如果[b, a | Tb]
为Tb
且Ta
的前两个元素已交换,则结果为a
。这是以b
和a
开头的任何列表的规则,但如果您有任何其他前两个元素,则该规则将无效,因为b
和swap12([1,2,3,4], L)
是 atoms ,而不是变量。因此,例如,1
将失败,因为您的列表以2
和a
开头,而不是b
和swap12(Ta, Tb)
。此外,您的问题是交换 ONLY 前两个元素,而您的解决方案具有递归调用?- swap12([a,b], R).
R = [b,a].
?- swap12([b,a], R).
false. % This fails because `b`, `a` doesn't match `a`, `b`.
?- swap12([a,b,c], R).
false. % This fails because [a,b,c] has an odd number of elements
?- swap12([a,b,c,d], R).
false. % This fails because `c`, `d` doesn't match `a` and `b`
?- swap12([a,b,a,b], R).
R = [b, a, b, a].
?- swap12(X, Y).
X = Y, Y = [] ;
X = [a, b],
Y = [b, a] ;
X = [a, b, a, b],
Y = [b, a, b, a] ;
X = [a, b, a, b, a, b],
Y = [b, a, b, a, b, a] ;
X = [a, b, a, b, a, b, a, b],
Y = [b, a, b, a, b, a, b, a] ;
...
,它继续以递归方式交换。
以下是您的代码实际执行的操作(它不会执行您在问题中显示的内容,这意味着您显示的结果是针对您编写的代码的不同版本)。
a
最后一次执行显示了您的规则的真正含义。仅当第一个列表为空或任意数量的b
,a
对且第二个列表相同且每个b
,b
对交换为{时,它才会成功{1}},a
。
让我们重新开始吧。同样,问题是创建一个规则,如果第二个列表是 ONLY 交换的前两个元素的第一个列表,则该规则为true。具有至少两个元素的列表看起来像[X, Y|T]
(前两个元素是X
和Y
- 变量)。如果我想交换 ONLY 前两个元素,我会写[Y, X|T]
所以我换了X
和Y
,但保持相同 tail,T
(我不想再交换任何元素)。
因此,该规则看起来像:
swap12([X, Y|T], [Y, X|T]).
这表示如果我有一个列表[X, Y|T]
,那么[Y, X|T]
是相同的列表,但只交换了前两个元素。你可以尝试一下:
?- swap12([a], R).
false. % fails because `[a]` only has one element!
?- swap12([a,b], R).
R = [b, a].
?- swap12([a,b,c], R).
R = [b, a, c].
?- swap12([a,b,c,d], R).
R = [b, a, c, d].
?- swap12([a,b,c,e,f], R).
R = [b, a, c, e, f].
?- ...