Как пользоваться онлайн-компилятором Prolog
- Напишите факты и правила в редакторе или начните с примера, нажав Сбросить пример.
- Укажите, что запускать, директивой
:- initialization(main)., гдеmain— предикат, который вызывает нужные вам цели и выводит результаты. - Нажмите Запустить или используйте Ctrl + Enter (⌘ + Enter на Mac). Программа загружается как файл
main.pl, а её директивы выполняются во время загрузки. - Смотрите напечатанный текст, ошибки и предупреждения на панели Результат. Выберите ограничение времени в 5, 15 или 60 секунд и нажмите Остановить, если рекурсия никогда не заканчивается.
Среда выполнения SWI-Prolog занимает около 4 МБ и после первого визита кешируется браузером. Сохраните программу кнопкой Копировать или скачав main.pl, меняйте размер текста кнопками A− и A+, переключайте расположение панелей кнопкой раскладки и используйте Полноэкранный режим (Ctrl/⌘ + Shift + F, выход — Esc) для длинных программ.
Всё работает в вашем браузере. Программа никогда не отправляется на сервер, а редактор сохраняет вашу последнюю версию только в локальном хранилище браузера.
Что поддерживается
Страница использует SWI-Prolog 10, скомпилированный в WebAssembly (swipl-wasm). Это настоящая система SWI-Prolog, а не упрощённый интерпретатор.
- Загрузка файла (consult): ваш код загружается точно так же, как это сделал бы
consult('main.pl'), поэтому работают и предложения, и операторы, и директивы. - Предикаты вывода:
format/2,write/1,writeln/1,print/1иnl/0выводят текст на панель результата. - Списки и предикаты для всех решений:
member/2,append/3,length/2,msort/2,findall/3,bagof/3,setof/3,forall/2. - Арифметика с
is/2и операторами сравнения, для целых и вещественных чисел. Значение20!в примере вычисляется точно. - Диагностика в том виде, в каком её печатает SWI-Prolog, например предупреждения об одиночных переменных и ошибки вроде
ERROR: ... Arithmetic: `foo/0' is not a function.
Чем это отличается от настольного Prolog:
- Нет интерактивного приглашения для запросов
?-, поэтому нельзя вводить запросы и нажимать;, чтобы получить другие ответы. Поместите запросы вmainи выводите ответы или собирайте их все с помощьюfindall/3илиforall/2. - Нет стандартного ввода. Предикату
read/1нечего читать, поэтому записывайте тестовые данные в виде фактов.
Основы Prolog в одной программе
% Факты
likes(mary, wine).
likes(john, wine).
likes(john, mary).
% Правило: X и Y — друзья, если им обоим нравится одно и то же
friends(X, Y) :- likes(X, Z), likes(Y, Z), X \== Y.
% Рекурсия по списку с аккумулятором
sum_list_acc([], Acc, Acc).
sum_list_acc([H|T], Acc0, Sum) :- Acc1 is Acc0 + H, sum_list_acc(T, Acc1, Sum).
% Отсечение (!) фиксирует выбор первого подходящего предложения
max(X, Y, X) :- X >= Y, !.
max(_, Y, Y).
main :-
findall(X-Y, friends(X, Y), Pairs), writeln(Pairs),
sum_list_acc([1,2,3,4], 0, S), format("sum = ~w~n", [S]),
max(3, 7, M), format("max = ~w~n", [M]).
:- initialization(main).
При запуске выводится [mary-john,john-mary], sum = 10 и max = 7.
Типичные ошибки
=— это унификация, а не присваивание и не арифметика.X = 1 + 2связываетXс термом1+2. Чтобы вычислить выражение, используйтеX is 1 + 2, а для сравнения двух чисел —=:=.- Переменные начинаются с заглавной буквы или с
_.name— это атом, аName— переменная, поэтому опечатка в регистре молча меняет смысл предложения. - Предупреждения об одиночных переменных означают, что переменная встречается в предложении только один раз, что обычно говорит об опечатке. Переименуйте её в
_или_Name, если она намеренно не используется. - Пользуйтесь отсечением осторожно. Приведённый выше
max/3подходит дляmax(3, 7, M), но второе предложение зависит от отсечения, поэтомуmax(5, 3, 3)ошибочно завершается успехом. Если записать второе предложение какmax(X, Y, Y) :- X < Y., оно станет безопасным. Неудачно поставленное отсечение может также скрыть решения, которые иначе вернул быfindall. - Левая рекурсия зацикливается. Правило вроде
ancestor(X, Y) :- ancestor(X, Z), parent(Z, Y).рекурсивно вызывает само себя бесконечно. Поставьте цельparentпервой.
main завершается неудачей вместо успеха, SWI-Prolog печатает предупреждение о том, что цель инициализации не выполнилась. Добавьте вызовы writeln/1 между целями, чтобы увидеть, докуда доходит выполнение.Часто задаваемые вопросы
Как выполнить запрос?
Напишите его внутри предиката, например main, и добавьте :- initialization(main). в конец файла. Цель можно также поместить прямо в директиву, например :- X is 2^10, writeln(X).
Это стандартный Prolog?
Это SWI-Prolog, который следует стандарту ISO и добавляет много расширений. Текст в двойных кавычках в SWI-Prolog — это строка, что важно, если вы привыкли, что он означает список кодов символов.
Можно ли получить все ответы на запрос?
Да. Используйте findall/3, чтобы собрать их в список, или forall/2, чтобы вывести каждый из них, как это делает программа-пример.
Есть ли другие логические или функциональные языки?
Попробуйте онлайн-интерпретатор Scheme или онлайн-компилятор Clojure, либо посмотрите все онлайн-компиляторы.
Обновлено