【问题标题】:Does any version of Prolog support higher order abstraction of accumulators?是否有任何版本的 Prolog 支持累加器的高阶抽象?
【发布时间】:2013-10-25 23:03:40
【问题描述】:

我想知道一个 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 的新手,可能会遗漏一些明显的东西。

【问题讨论】:

  • 在 Mercury 中,人们只需编写一个名为 accum 的谓词来执行此操作。但是,您不能将目标用作参数(正如您在问题中所做的那样),您必须改用 lambda。
  • @PaulBone 结果取决于计算生成器的所有解决方案。所以,最终,仍然需要从 Mercury 的 solutions 模块调用某些东西,除非您想使用非逻辑功能(在这种情况下,副词“简单地”不适用;))。

标签: prolog mercury


【解决方案1】:

SWI-Prolog library(aggregate) 有一个强大的接口,例如

aggregate_all(sum(Val), member(Val,List), Sum)

聚合和生成之间的变量共享(显然很简单)是通过您可能感兴趣的谓词foreach/2 获得的。

在 SWI-Prolog 中,您可以通过 ?- edit(library(aggregate)). 来研究内部结构...

library(aggregate) 效率相对较低,但加上 SWI-Prolog nb_ (non backtrackable) 数据结构应该可以很好地完成它的工作......

关于不可回溯的数据结构:here 是我的“自建”累加器的一个示例,通过 nb_setarg/3 实现。

【讨论】:

    【解决方案2】:

    我假设您的意思是没有显式递归?如果是这样,您可以使用高阶谓词列表 fold left 的实现,以及 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 left 谓词遍历列表,递归地将其第一个参数中的闭包应用于列表元素和累加器,返回最终的累加器值。

    【讨论】:

    • 问题是要求通过回溯生成解决方案。您的回复以已经生成的解决方案 [1,2,3] 开头,因此它没有回答问题。
    • [1,2,3]not 解决方案列表,它是 input 列表,与您在 member(Val,List) 位中传递的相同在问题示例中。
    • 你只解决了例子,没有解决一般情况。问题很明显,我重复一遍,要求通过回溯生成解决方案。
    【解决方案3】:

    在 Mercury 的标准库中,“解决方案”模块提供了类似的功能。

    请注意,X is X + Val 不会为 X 分配新值。如果 Val 为零,则该语句为 true,如果为任何其他数字,则为 false,这可能不是您的意思。像这样的累加器通常表示为初始值和最终值之间的关系。

    在 Mercury 中,您的示例可以写成:

    :- 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).
    

    不需要单独的过滤器参数,因为它可以作为生成器的一部分。

    【讨论】:

      猜你喜欢
      • 2015-03-29
      • 2018-04-30
      • 2016-07-15
      • 1970-01-01
      • 1970-01-01
      • 2016-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多