Как суммировать значения предикатов без использования списка? - PullRequest
2 голосов
/ 25 июня 2019

Я пытаюсь суммировать значения из предикатов без использования списка. Суммирование значений и, наконец, сумма всех этих значений.

%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 должен вернуть общую стоимость, например, общая стоимость магазина (1, пепел, 12) составит 65.

1 Ответ

5 голосов
/ 26 июня 2019

Технически правильным ответом на ваш вопрос будет использование предикатов из библиотеки (агрегат). Простой запрос:

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

Вы видите, нигде нет списка! Ну, кто знает, может быть, есть списки, скрывающиеся за aggregate_all, но мы их не видим, амирит?

Способ агрегирования без создания структуры данных в постоянной памяти заключается в использовании глобального состояния. Обычно это не рекомендуется по двум причинам:

  1. В общем, глобальное состояние трудно поддерживать;
  2. В частности, в Прологе код для манипулирования глобальным состоянием неудобен для написания.

Вот как вы можете перебирать факты и получать побочный эффект:

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

Первый аргумент forall - это генератор (в данном случае те строки в таблице cart/3, у которых 1 в первом аргументе). Второй аргумент forall - это побочный эффект. Теперь вам нужно только добавить глобальную переменную вместо печати в стандартный вывод:

?- 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.

(И, пожалуйста, смотрите комментарий ниже.)

Вы могли бы использовать другие механизмы для сохранения глобального состояния. Наиболее переносимым было бы вставить (ну, assert) в таблицу с одной строкой, затем на каждом шаге читать и удалять значение в этой строке (с retract), добавлять к нему и assert результат обратно. Я видел этот танец в реляционных базах данных, если вам нужно сохранять действительно глобальное состояние для собственного (на уровне приложения) учета.

При обычном использовании это не нужно. Однако , полезно знать, как это делается, вот почему я потрудился написать все это. Мы не можем иметь это "ты не можешь иметь это" дерьмо.

...