Технически правильным ответом на ваш вопрос будет использование предикатов из библиотеки (агрегат). Простой запрос:
?- aggregate_all(sum(Price), cart(1, _, Price), Total).
Total = 65.
Вы видите, нигде нет списка! Ну, кто знает, может быть, есть списки, скрывающиеся за aggregate_all
, но мы их не видим, амирит?
Способ агрегирования без создания структуры данных в постоянной памяти заключается в использовании глобального состояния. Обычно это не рекомендуется по двум причинам:
- В общем, глобальное состояние трудно поддерживать;
- В частности, в Прологе код для манипулирования глобальным состоянием неудобен для написания.
Вот как вы можете перебирать факты и получать побочный эффект:
?- 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
результат обратно. Я видел этот танец в реляционных базах данных, если вам нужно сохранять действительно глобальное состояние для собственного (на уровне приложения) учета.
При обычном использовании это не нужно. Однако , полезно знать, как это делается, вот почему я потрудился написать все это. Мы не можем иметь это "ты не можешь иметь это" дерьмо.