我想知道Prolog可能包含这样的内置调用:
accum(generator, filter, accumulator)
Calculates all solutions to generator.
For each one, if filter can be proved, accumulator is proved.
Backtracks to find all solutions to filter and generator.
Accumulator may backtrack internally, but multiple proofs of accumulator are
conjoined, not backtracked.
因此,例如,要在不使用递归的情况下对列表求和,您可以编写:
X is 0, accum(member(Val,List), True, X is X + Val).
是否有任何Prolog与此结构或等效?请记住,我是Prolog的新手,可能会遗漏一些明显的东西。
答案 0 :(得分:5)
SWI-Prolog library(aggregate)具有强大的界面,例如
aggregate_all(sum(Val), member(Val,List), Sum)
聚合和生成之间的(显然简单的)变量共享是通过您可能感兴趣的谓词foreach / 2获得的。
在SWI-Prolog中,你可以?- edit(library(aggregate)).
来研究内部......
库(聚合)效率相对较低,但加上SWI-Prolog nb_(非可回溯)数据结构应该可以很好地完成它的工作......
答案 1 :(得分:3)
我假设您的意思是没有显式递归?如果是这样,您可以使用左侧高阶谓词列表的实现以及lambda表达式来避免需要辅助谓词。以Logtalk为例,您可以写:
?- Sum0 is 0, meta::fold_left([X,Y,Z]>>(Z is Y+X), Sum0, [1,2,3], Sum).
Sum0 = 0,
Sum = 6.
Logtalk可以用作大多数Prolog实现的后端编译器(http://logtalk.org/)。您还可以使用Ulrich的lambda
库(http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord.html)和支持的Prolog编译器以及Prolog库,为同一结果提供折叠左谓词。现在使用YAP作为例子:
$ yap
...
?- use_module(library(lambda)).
...
?- use_module(library(maplist)).
...
?- Sum0 is 0, foldl(\X^Y^Z^(Z is Y+X), [1,2,3], Sum0, Sum).
Sum = 6,
Sum0 = 0.
简而言之,fold左谓词在列表上迭代,递归地将第一个参数中的闭包应用于list元素和累加器,返回最终的累加器值。
答案 2 :(得分:2)
在Mercury的标准库中,"解决方案"模块提供这样的功能。
请注意,X is X + Val
不会为X分配新值。如果Val为零,则该语句为true;如果为任何其他数字,则为false,这可能不是您的意思。像这样的累加器通常表示为初始值和最终值之间的关系。
在水星中,你的例子可以写成:
:- import_module solutions.
...
sumlist(List, Sum) :-
Generator = (pred(Val::out) is nondet :- member(Val, List), true),
Accumulator = (pred(X::in, Y::in, Z::out) is det :- Z = X + Y),
aggregate(Generator, Accumulator, 0, Sum).
不需要单独的过滤器参数,因为它可以作为生成器的一部分包含在内。