我们可以按如下方式合并两个排序列表

merge_([A|T], [], [A|T]).
merge_([], [A|T], [A|T]).
merge_([A|T], [B|U], [A|V]) :- A @< B, merge_(T, [B|U], V).
merge_([A|T], [B|U], [B|V]) :- A @>= B, merge_([A|T], U, V).

在一个方向上工作正常。对这个定义不起作用的是像 merge_(A, [a, b, c], [a, b, c, d]). 之后的查询,尽管有一个独特且非常明显的解决方案 A = [d]. 。即使迭代 merge_(A, B, [a, b, c]). 也应该产生相当简单的结果集:A[a, b, c]B = [a, b, c] \ A 的有序子集。

如何更改 merge_ 的定义以使其适用于所有方向?

最佳答案

@mat 的回答是准确的。当将问题限制为整数时,您将受益于 CLP(FD) 运算符,因为它们了解域(或“可能值的宇宙”)。

不幸的是,A @< B 无法先验地知道 AB 的可能值是什么,因此无法“提出”任何可能的解决方案。例如,如果您有一个谓词 valid(X) 对可能值域中的 X 为真,您可以编写 valid(A), valid(B), A @< B, ... 。这是一个人为的例子,它展示了如果你知道你关心的可能原子的有限域是如何工作的。

    valid(X) :- member(X, [a,b,c,d,e,f,g,h,i,j,k,l,m,n]).

    merge_([A|T], [], [A|T]).
    merge_([], [A|T], [A|T]).
    merge_([A|T], [B|U], [A|V]) :- valid(A), valid(B), A @< B, merge_(T, [B|U], V).
    merge_([A|T], [B|U], [B|V]) :- valid(A), valid(B), A @>= B, merge_([A|T], U, V).

既然我们已经限制 AB 存在于特定的有限值域中,您的谓词可以“反向”工作:
| ?- merge_(A, [a, b, c], [a, b, c, d]).

A = [d] ? a

no
| ?- merge_(A, B, [a, b, c]).

A = [a,b,c]
B = [] ? a

A = []
B = [a,b,c]

A = [a]
B = [b,c]

A = [a,c]
B = [b]

A = [a,b]
B = [c]

A = [b,c]
B = [a]

A = [b]
B = [a,c]

A = [c]
B = [a,b]

no
| ?-

关于list - 可逆合并,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38587088/

10-13 00:01