这是无法按预期工作的解决方案:
(1) comb([], [], []).
(2) comb([H|T], [X|Y], [H,X]).
(3) comb([H,T|T1], [X,Y|T2], [T,Y]).
(4) comb([H|T], [X|Y], L) :-
comb(T, Y, [H|X]).
(1) 说,将一个空列表与一个空列表组合是一个空列表。 这听起来逻辑上是正确的。
(2) 说,[H,X] 是来自[H|T] 和[X|Y] 的一对元素。确实如此(仅提供解决方案的一种组合)。
(3) 说,[T,Y] 是来自[H,T|T1] 和[X,Y|T2] 的一对元素。这也是正确的(只为解决方案提供了一种其他组合,与 #2 不同)。
(4) 说,L 是一对来自[H|T] 和[X|Y] 的元素,如果[H|X] 是一对来自T 和Y 的元素。这不可能是真的,因为L 没有出现在子句的结果中,所以它永远不会被实例化。
上述解决方案被过度考虑并且比它需要的更复杂。它失败了,因为它硬编码了两个解决方案(匹配前两个元素和后两个元素)。递归子句是错误的,因为它没有逻辑基础,解决方案被保留为单例变量。
首先,您需要确定谓词的含义。在这个特定问题中,如果P 是一对(比如[X,Y]),其中X 来自Xs(即, X 是 Xs 的成员,Y 来自 Ys(Y 是 Ys 的成员)。然后,当您查询谓词时,它会提示您提供每个解决方案,直到找到所有解决方案。
这个问题可以用一条规则来说明:[X,Y] 是分别取自Xs 和Ys 的元素的组合,如果X 是Xs 和Y 的成员是Ys 的成员。这听起来像是一个微不足道的真实陈述,但这就是解决这个问题所需要的全部内容。
把它翻译成 Prolog 得到这个:
comb(Xs, Ys, [X,Y]) :- % [X,Y] is combination of elements from Xs and Ys if...
member(X, Xs), % X is a member of Xs, and
member(Y, Ys). % Y is a member of Ys
现在让我们试试吧:
| ?- comb([1,2],[3,4],P).
P = [1,3] ? ;
P = [1,4] ? ;
P = [2,3] ? ;
P = [2,4]
(2 ms) yes
| ?-
它找到了所有的组合。我们让 Prolog 完成所有工作,我们只需要声明规则是什么。
如果您想将所有结果收集到一个列表中,可以使用内置谓词,例如findall/3:
| ?- findall(P, comb([1,2], [3,4], P), AllP).
AllP = [[1,3],[1,4],[2,3],[2,4]]
yes
| ?-
然后瞧。 :)
您还可以非常轻松地概括解决方案,并从给定列表的每个列表中选择一个元素。在这里,multicomb/2 有一个列表列表作为第一个参数(例如、[[1,2]、[3,4]]`,并生成每个元素的组合,每个组合一个子列表:
multicomb([L|Ls], [X|Xs]) :-
member(X, L),
multicomb(Ls, Xs).
multicomb([], []).
这给出了:
| ?- multicomb([[1,2],[3,4]], P).
P = [1,3] ? a
P = [1,4]
P = [2,3]
P = [2,4]
yes
| ?-
还有:
| ?- multicomb([[1,2],[a,b],[x,y,z]], P).
P = [1,a,x] ? a
P = [1,a,y]
P = [1,a,z]
P = [1,b,x]
P = [1,b,y]
P = [1,b,z]
...