所以我对prolog很新,当整数列表D是列表A的前缀和列表时,必须编写一个可满足的谓词。
sums(A, D)
例如,
sums([4,11,1,-3,8], [4,15,16,13,21]) is satisfiable
我已经用十几种不同的方式写了这个谓词无济于事。这就是我目前所写的内容。
sums([], []).
sums([A], [A]).
sums([A|[B|C]], [A|[E|F]]) :- TOTAL is A + B, E = TOTAL, sums([C], [F]).
这有点起作用,因为它将检查每个列表的第一个值是否相等,并且还检查列表中的第二个元素是否正确,因为它应该是15.我理解为什么它以这种方式不正确地工作,但我无法以正确的方式提出不同的写法。
我已将代码更改为
sumrunner(L, S) :- sumrunner(L, S, 0).
sumrunner([], [], _).
sumrunner([A], [A], _).
sumrunner([A|B], [C|D], TOTAL) :- TOTAL is TOTAL + A, TOTAL = C,sumrunner(B, D, TOTAL).
然而,现在它只是对所有情况都说假,除了两个列表都是空的,并且列表都包含一个元素并且它们彼此相等时。
答案 0 :(得分:3)
您应该详细了解列表符号:例如,[A|[B|C]]
可以写为[A,B|C]
。现在更清楚的是C
是列表的尾部,因此,它本身就是一个列表!因此,当您编写sums([C], [F])
时,您将C
和F
包装到列表中,即使它们已经是列表,这也是您的问题。
如果我们修复此问题并运行您的谓词,我们就会得到:
?- sums([4,11,1,-3,8],Z).
Z = [4, 15, 1, -2, 8]
你可以看到它仍然是错误的。主要问题是,第三条规则中的递归调用sums
表示列表尾部的前缀和是列表前缀和的尾部,这是错误的,因为这些前缀和取决于上一个元素!
要解决这个问题,您需要引入一个额外的参数来维持递归调用的总和值:
:- use_module(library(clpfd)).
prefix_sums(L, D) :-
prefix_sums(L, 0, D).
prefix_sums([], _, []).
prefix_sums([H|T], S, [S1|T2]) :-
S1 #= H + S,
prefix_sums(T, S1, T2).
使用library(clpfd)
,我们得到了我们期望的行为:
?- prefix_sums([4,11,1,-3,8],Z).
Z = [4, 15, 16, 13, 21].
但也有相反的行为:
?- prefix_sums(Z, [4,15,16,13,21]).
Z = [4, 11, 1, -3, 8].
并且用更少的信息来纠正行为:
?- prefix_sums([A,B,C],Z).
Z = [A, _7964, _7970],
B+A#=_7964,
C+_7964#=_7970.
?- prefix_sums(X,Z).
X = Z, Z = [] ;
X = Z, Z = [_7122],
_7122 in inf..sup ;
X = [_7452, _7458],
Z = [_7452, _7482],
_7458+_7452#=_7482 ;
X = [_7770, _7776, _7782],
Z = [_7770, _7806, _7812],
_7776+_7770#=_7806,
_7782+_7806#=_7812 ;
…
答案 1 :(得分:2)
您的代码必须经过简化:
sums(L, S) :- sumrunner(L, S, 0).
sumrunner([], [], _).
sumrunner([A|B], [C|D], TOTAL) :- C is TOTAL + A, sumrunner(B, D, C).
?- sums([4,11,1,-3,8], [4,15,16,13,21]).
true.
?- sums([4,11,1,-3,8], [4,15,16,14,21]).
false.
表达式C is TOTAL + A
都检查需求并更新累加器以进行递归步骤。