Запись базы данных Пролога

У меня есть этот факторный предикат.

fact(0, 1).
fact(N, F) :- N > 0, 
        N1 is N-1,
        fact(N1, F1),
        F is F1 * N.

Как изменить этот предикат таким образом, чтобы при каждом запросе результат расчета сохранялся в базе данных? Новые запросы должны использовать сохраненные результаты, если они доступны.

2 ответа

Решение

То, что вы ищете, обычно называется запоминанием, но в контексте Пролога называется табулированием. Удобно, что есть библиотека для этого, называемая таблингом для SWI Prolog.

:- use_module(library(tabling)).
:- table fact/2.

fact(0, 1).
fact(N, F) :- N > 0,
              N1 is N-1,
              fact(N1, F1),
              F is F1 * N.

Вы можете проверить, что памятка работает, запустив trace до ваших звонков fact, Обратите внимание, что два :- Строки называются директивами и запускаются компилятором, поэтому запуск их в repl не будет работать.

редактировать

Если вы не хотите использовать библиотеку табулирования, вы можете сделать это с помощью asserta. Это вставит факт вверху базы данных, как если бы вы ввели его в файл самостоятельно.

fact(0, 1).
fact(N, F) :-
              N > 0,
              N1 is N-1,
              fact(N1, F1),
              F is F1 * N,
              asserta(fact(N, F)).

Пролог сначала увидит новый предикат и будет использовать его вместо пересчета факториала. Еще раз, вы можете проверить это путем отслеживания.

Как сказал jcolemang, все, что вам нужно, это табулирование / запоминание. Хотя действительно есть библиотеки, которые являются рекомендуемым и эффективным (не только с точки зрения времени, но в основном с точки зрения производительности) способом, вполне понятно, что вы можете реализовать его самостоятельно.

Можно использовать assert для добавления динамических фактов в базу данных пролога, но вам нужно объявить их как таковые, имея :-dynamic(fact) в файле, который позволит вам добавлять / удалять факты.

Тем не менее, это приводит к снижению производительности. Альтернативой может быть наличие справочной таблицы / кэша, которая будет сохраняться при вызовах. Словарь может храниться с использованием глобальных изменяемых переменных (yikes!), Которые более эффективны, чем динамические факты. Как всегда, неплохо бы минимизировать код, который напрямую использует переменные / побочные эффекты - в вашем факториальном примере вы могли бы просто иметь предикат-обертку, который выбирает словарь и возвращает его в конце вызова, например

factorial(N, F):-
get_global_dict(D),
real_factorial(N, F, D, DF),
store_global_dict(DF).
Другие вопросы по тегам