将Haskell转换为Prolog-查找和的子列表
我正在尝试翻译以下Haskell代码:将Haskell转换为Prolog-查找和的子列表,haskell,prolog,list-comprehension,sublist,prolog-findall,clpfd,Haskell,Prolog,List Comprehension,Sublist,Prolog Findall,Clpfd,我正在尝试翻译以下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 <- sub
-- 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
如果由于1+2+3=6而绑定,则应为您提供[[1,2,3]]
。
这就是我到目前为止所做的:
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)).
仍然给我同样的结果。不太清楚我到底做错了什么 Prolog代码中有几个基本问题:
是一个Prologatom,因此它永远不会与列表统一sum
- 在Prolog中,我们定义了实体之间的关系,并且需要谓词参数来引用这些实体
xs
和sum
是原子,而Prolog变量以大写字母或小写字母开头
此外,如果您继续尝试直译,您将失去真正受益于关系的普遍性的机会。典型的序言谓词不仅可以在一个方向上使用,还可以在多个方向上使用,您不仅可以使用它们进行计算,还可以使用它们测试和完成部分结果
因此,我想向您展示这个任务的一个更加地道的序言解决方案,而不是直译 我们的第一个观察结果,从类型签名中可以清楚地看出:我们正在对整数进行推理。因此,我建议您使用Prolog系统的CLP(FD)约束来实现完全声明性整数算法。有关此功能的详细信息,请参阅 第二,任务可以被视为“过滤”列表,为此,我们使用提供的
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).
此示例处于原始函数的范围内:第一个和第二个参数完全指定,第三个参数用于表示“结果”
然而,正如Prolog的典型情况一样,我们还可以进行更多的一般的查询,其中不仅“结果”是未指定的,而且其他部分也是未指定的。显然,这远远超出了函数的范围,而原始代码的直译可能没有这方面的好处
例如:
?- sublist_sum([[1,2,N]], 6, Ls).
注意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).
-子列表_sum([[A,B,C]],sum,Ls)。
Ls=[[A,B,C]],
A+B+C#=总和;
Ls=[],
A+B+C=U 15806,
_15806#=为了简单起见,有没有一种方法可以在不使用库(reif)的情况下解决这个问题?如果您想破坏代码的声明性含义,广泛使用的谓词
include/3
是一种很好的方法,因为它只对其中一个分支进行不可加性的提交,即使这两个分支仍然适用。您可以很容易地找到一个实现,也可以自己实现它。生成的代码可能和Haskell版本一样有限。好的,明白了。另外,我不明白为什么sum_intlist(sum)用一个变量调用,而sum_intlist(sum,Ls,t)需要三个变量?我试着运行它,结果它给了我一个错误。对不起,所有的问题。这是一个结束,或者,正如你在Haskell中所说的,部分应用。谓词tfilter/3
总是使用两个附加参数调用闭包:list元素和truth值,以决定是否必须包含该元素。当然,这两个选项都可能适用,在这种情况下,两个答案都是回溯生成的tfilter/3
在安全的情况下自动提交到其中一个分支,即由于参数已被充分实例化而无法应用其他分支时。sum\u intlist
而不是sum\u intlist\t
?
?- sublist_sum([[1,2,N]], 6, Ls).
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.
?- 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).
?- sublist_sum([[1,2,3]], 5, []).
true.