modThreeModFive(X) :- X > 0, X < 1000, 0 is mod(X, 5) ; 0 is mod(X, 3).

Мне интересно, как проще всего получить сумму значений X, для которых утверждение верно, учитывая, что количество решений конечно.

Возможно ли это вообще в Прологе, или я вынужден заполнять список целыми числами [1, 1000], а затем тестировать их по отдельности?

0
Uclydde 12 Июн 2020 в 23:02

1 ответ

Лучший ответ

Поскольку язык настолько отличается от императивных языков, самый простой способ - использовать предикат библиотеки :

?- [user].
|: modThreeModFive(X) :- X > 0, X < 1000, 0 is mod(X, 5) ; 0 is mod(X, 3).
|: 
% user://1 compiled 0.05 sec, 1 clauses
true.

?- aggregate(sum(X),(between(1,1000,X),modThreeModFive(X)),Sum).
Sum = 266333.

Не в каждом Прологе есть такая библиотека, тогда альтернативой будет - как вы уже предложили - сначала получить список значений, а затем суммировать их:

?- findall(X,(between(1,1000,X),modThreeModFive(X)),L),sumlist(L,Sum).
L = [3, 5, 6, 9, 10, 12, 15, 15, 18|...],
Sum = 266333.

Если ваш Пролог допускает присваивание без возврата, вы можете самостоятельно реализовать некоторые из основных функций, имеющихся в библиотеке (агрегат).

ОТ: версия, суммирующая список, показывает ошибку в вашей логике: 15 - решение в обеих ветках. Вместо дизъюнкции следует использовать конструкцию if / then / else. Как в

?- [user].
|: modThreeModFive(X) :- 0 is mod(X, 5) -> true ; 0 is mod(X, 3).

Warning: user://2:21:
Warning:    Redefined static procedure modThreeModFive/1
Warning:    Previously defined at user://1:8
|: 
% user://2 compiled 0.00 sec, 1 clauses
true.

?- findall(X,(between(1,1000,X),modThreeModFive(X)),L),sumlist(L,Sum).
L = [3, 5, 6, 9, 10, 12, 15, 18, 20|...],
Sum = 234168.

Или просто вырезать ! / 0 , чтобы зафиксировать первый результат . Полезное упражнение - найти правильную позицию в таком простом предикате ...

2
CapelliC 13 Июн 2020 в 08:23