我正在尝试翻译以下Haskell代码:
-- sublistSums list sum returns a list of the sublists of list that add up to sum
sublistSums :: [Int] -> Int -> [[Int]]
sublistSums [] 0 = [[]]
sublistSums [] _ = []
sublistSums (x:xs) sum = [x:tailList | tailList <- sublistSums xs (sum-x)] ++
sublistSums xs sum
...进入Prolog。该代码应该给我一个列表,列出其总和加起来的目标号码。例如,
?- sublistSums([[1,2,3],[4,5,6]],6).
如果因为[[1,2,3]]
1+2+3=6.
这是我到目前为止所做的:
sublistSums([], 0) :-
sublistSums([],0,[]).
sublistSums([], _) :-
sublistSums([],0,[]).
sublistSums([x|xs], sum) :-
conc(conc(x,findall(xs,(sublistSums(xs, (sum-x))),List)), sublistSums(xs, sum)).
然而,当我调用sublistSums函数时,它给了我:
?- sublistSums([[1,2,3],[4,5,6]],6).
false.
我也尝试过:
sublistSums([], 0, ReList) :-
[[]].
sublistSums([], _, ReList) :-
[].
sublistSums([x|xs], sum, ReList) :-
conc(conc(x,findall(xs,(sublistSums(xs, (sum-x)),ReList),List)), sublistSums(xs, sum, ReList)).
仍然给我相同的结果。不完全确定我在这里做错了什么。
答案 0 :(得分:4)
您的Prolog代码中存在一些基本问题:
sum
是Prolog atom ,因此永远不会与列表统一。因此,您无法翻译代码 verbatim 。如果您例如引入一个新的参数来保存原始函数的返回值,那么仍然可以使用完全字面的Haskell→Prolog转换。你的第二个片段是朝这个方向发展的,但它并不是独立的,也包含几个错误。例如,xs
和sum
是 atoms ,而Prolog 变量以大写字母或下划线开头。
此外,如果您继续尝试文字翻译,您将放弃真正从关系的普遍性中受益的机会。典型的Prolog谓词不仅可以在 one 中使用,而且可以在几个方向中使用,并且您不仅可以将它们用于计算,还可以使用它们测试和完成部分结果。
因此,我想向您展示一个更强大的惯用 Prolog解决方案,而不是字面翻译。
我们的第一个观察结果,从类型签名中可以清楚地看出:我们推理整数。因此,我建议您使用Prolog系统的 CLP(FD)约束进行完全声明性整数运算。有关此功能的详情,请参阅clpfd。
其次,该任务可以被视为“过滤”列表,为此,我们使用library(reif)提供的tfilter/3
。
以下是完整的Prolog解决方案:
sublist_sum(Lss0, Sum, Lss) :- tfilter(sum_intlist(Sum), Lss0, Lss). sum_intlist(Sum, Ls, T) :- sum(Ls, #=, Sum0), zcompare(C, Sum0, Sum), eq_truth(C, T). eq_truth(=, true). eq_truth(<, false). eq_truth(>, false).
将此谓词视为关联列表Lss0
, sum 和第二个列表Lss
,以便您声明所有要求是满意的。请注意,我没有说这些参数中的哪一个是“给定的”,因为它们中的任何一个都可能完全,部分或完全没有指定。
您的示例按要求运行:
?- sublist_sum([[1,2,3],[4,5,6]], 6, Ls). Ls = [[1, 2, 3]].
此示例保持在原始函数的范围内:第一个和第二个参数已完全指定,第三个参数用于表示“结果”。
然而,正如Prolog的典型情况一样,我们还可以进行更多一般查询,其中不仅“结果”,还有其他部分未指定。显然,这远远超出了函数的范围,原始代码的字面翻译可能没有这个好处。
例如:
?- sublist_sum([[1,2,N]], 6, Ls).
在这种情况下,我们已离开N
未指定,并要求Prolog考虑可能适用于N
的所有案例。
作为回应,Prolog 生成不同的可能性,以分离表示:
N = 3, Ls = [[1, 2, 3]] ; Ls = [], N in inf..2, -3+_10694#=N, _10694 in inf..5 ; Ls = [], N in 4..sup, -3+_10662#=N, _10662 in 7..sup.
请注意Ls
取决于N
。
我们还可以进一步概括进一步,甚至不指定总和:
?- sublist_sum([[A,B,C]], Sum, Ls). Ls = [[A, B, C]], A+B+C#=Sum ; Ls = [], A+B+C#=_15806, _15806#=<Sum+ -1, zcompare(<, _15806, Sum) ; Ls = [], A+B+C#=_15806, Sum#=<_15806+ -1, zcompare(>, _15806, Sum).
再次,Prolog列举了不同的案例。
此外,我们可以专门化查询并将其用于测试关系:
?- sublist_sum([[1,2,3]], 5, []). true.
在这里,我们已经问过:这个具体案例是否持有?,Prolog以true
回复,表明该关系完全符合预期情况下。