如何在不使用列表的情况下对谓词值求和?

How to sum predicates values without using list?

我试图在不使用列表的情况下对谓词的值求和。对值求和,最后得到对这些值求和的总和。

%shop(TicketNumber, Client, Month).
shop(1, ash, 12).
shop(2, nelson, 11).
shop(3, rob, 10).

%cart(TicketNumber, Product, Price).
cart(1, eggs, 15).
cart(1, milk, 20).
cart(1, meat, 30).
cart(2, eggs, 10).
cart(2, soil, 5).

totalCostShop应该return总成本,例如shop(1, ash, 12)总成本为65。

您问题的技术正确答案是使用库中的谓词(聚合)。一个简单的查询:

?- aggregate_all(sum(Price), cart(1, _, Price), Total).
Total = 65.

你看,任何地方都没有列表!好吧,谁知道呢,也许 aggregate_all 后面隐藏着列表,但我们看不到它们,amirite?

一种无需在常量内存中创建数据结构即可进行聚合的方法是使用全局状态。通常不推荐这样做,原因有二:

  1. 总的来说,全局状态很难维护;
  2. 特别是在 Prolog 中,用于操纵全局状态的代码编写起来很笨拙。

以下是迭代事实并产生副作用的方法:

?- forall(cart(1, _, Price), format("~w~n", [Price])).
15
20
30
true.

forall 的第一个参数是生成器(在本例中,cart/3 table 中的那些行在第一个参数中具有 1forall 的第二个参数是副作用。现在你只需要添加到全局变量而不是打印到标准输出:

?- nb_setval(total, 0),
   forall(cart(1, _, Price),
   (   nb_getval(total, X0),
       X1 is X0 + Price,
       nb_setval(total, X1)
   )),
   nb_getval(total, Total).
Total = 65.

(请看下面的评论。)

您可以使用其他机制来保持全局状态。最 portable 将插入(嗯,assert)到具有单行的 table,然后在每个步骤中读取和删除该行上的值(使用 retract), 添加到它,然后 assert 结果返回。我在关系数据库中看到过这种情况,如果你需要为自己保留一个真正的全局状态 (application-level) book-keeping.

在正常使用中这是不必要的。 但是,知道它是如何完成的是很有用的,这就是为什么我不厌其烦地写下所有这些。我们不能有这个 "you can't have this" 狗屎。