Программы на языке Prolog выполняются не так, как в других языках программирования. Как уже говорилось в предыдущих уроках, задача Prolog программы доказать какое–либо утверждение и для этого используются логические операции, которые были рассмотрены в предыдущем уроке. В этом уроке мы рассмотрим, как Prolog выполняет программы и использует алгоритм поиска с возвратом.
В предыдущем уроке мы изучили предикаты конъюнкции и дизъюнкции. Подумайте, что выведет следующий код:
write('Hello, '), write('Hello, ') ; write('Hexlet!'), write('World!').
Hello, Hello, true ; Hexlet!World! true.
Как говорилось в предыдущем уроке, конъюнкция – логическое "И", а дизъюнкция – логическое "ИЛИ".
Благодаря конъюнкции первые и последние два оператора были выполнены вместе, а полученные результаты были выведены раздельно. Код выше можно прочитать так:
Выведи строку 'Hello, ' И строку 'Hello, ' ИЛИ выведи строку 'Hexlet!' И выведи строку 'World!'. Предикат write
возвращает "ИСТИНУ" (true). Таким образом Prolog нашел два подходящих решения.
А что выведет следующий код?
write(p), (write(q) ; write(r)), write(t).
pqt true ; rt true.
Почему вывод получился именно таким и почему буква 't' вывелась два раза, если в коде только один вывод этой буквы? Все дело в том, как Prolog интерпретирует программу. Фактически программа будет находить все возможные решения, которые в конечном итоге подтвердят утверждение. Для выполнения этой задачи Prolog использует поиск с возвратом (backtracking). Программа перебирает все возможные решения, возвращаясь в разные точки, в которых могло произойти разветвление решения на разные варианты.
Давайте разберем пример выше:
write(p)
и переходит к следующему предикатуwrite(q) ; write(r)
. Они соединены логическим "ИЛИ", которое разбивает решение на 2 разных. Фактически это означает, что программа может выполнить один предикат "ИЛИ" другойwrite(t)
и выполняет его. Программа должна бы завершиться, но мы помним, что у нас был предикат "ИЛИ", который разделил решение на 2 разных;
, но выполняет уже следующий предикат write(r)
, а за ним и оставшийся предикат write(t)
Совет: вывести все решения сразу можно, дописав в конце
, nl, fail.
. Получится такой код:
write(p), (write(q) ; write(r)), write(t), nl, fail.
Расставьте предикаты ,
и ;
так, чтобы программа вывела:
a true ; bc true.
Команда проекта находится в телеграм-сообществе по ссылке https://ttttt.me/HexletLearningBot. Там можно задать любой вопрос и повлиять на проект
Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник". Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи. В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества
Привет! Я Тота и моя задача помочь в обучении. Чтобы активировать меня, нужно зарегистрироваться или залогиниться, если у вас уже есть аккаунт
Ваше упражнение проверяется по этим тестам
1:- style_check(-singleton).
2:- dynamic error_happened/1.
3
4:- assertz(error_happened('OK')).
5
6user:message_hook(Term, error, _Lines) :-
7 retract(error_happened('OK')),
8 assertz(error_happened(error)),
9 fail.
10:- include(main).
11:- forall(call(writer), (nl, write('true ;'), nl)).
12
13:- begin_tests(backtracking).
14
15test(040, Output == 'a\ntrue ;\nbc\ntrue ;\n') :-
16 with_output_to(atom(Output), forall(call(writer), (nl, write('true ;'), nl))),
17 error_happened(X).
18
19:- end_tests(backtracking).
Решение учителя откроется через: