Пролог, ошибка при запросе ложного утверждения
input :-
read_line_to_codes(user_input, Input),
string_to_atom(Input,Atoms),
atomic_list_concat(Alist, ' ', Atoms),
phrase(sentence(S), Alist),
action(S).
statement(Rule) --> [Noun, 'is', 'a', Object], { Rule =.. [Object, Noun]}.
statement1(Rule) --> ['A', Noun, 'is', 'a', Object], { Rule =.. [Object, Noun]}.
query(Fact) --> ['Is', Noun, 'a', Object], { Fact =.. [Object, Noun]}.
sentence(statement(S)) --> statement(S).
sentence(statement1(S))--> statement1(S).
sentence(query(Q)) --> query(Q).
action(statement(S)) :- asserta(S) -> write(ok).
action(statement1(S)) :- asserta(S) -> write(ok).
action(query(Q)) :-( Q -> write(yes); write(unknown)), nl.
Задача состоит в том, чтобы создавать правила из пользовательского ввода в форме "_ is _." или "A _ является _." Это должно ответить "хорошо".
И тогда сможете запросить "_ _ _?" И ответьте "да" или "неизвестно". Я понятия не имею, почему он выдает ошибку, если предикат (я думаю, это то, что он называется, "ветчина") не находится в базе данных, но его хорошо с другой частью, которой там нет. Есть идеи, что я делаю не так? И извините, если я делаю что-то просто глупое, впервые с прологом. Я использую SWI-Prolog V.6.2.6, если это имеет значение. И как бы я пропустить истинное или ложное возвращение в выходе
11 ?- input.
|: john is a dog
ok
true .
12 ?- input.
|: Is john a dog
yes
true.
13 ?- input.
|: Is abraham a dog
unknown
false.
14 ?- input.
|: Is john a ham
ERROR: action/1: Undefined procedure: ham/1
Exception: (8) ham(john) ?
1 ответ
Во-первых, то, на что реагирует Prolog, это деталь реализации. SWI отвечает "true", но некоторые другие реализации отвечают "ok". Из-за этого в вашем коде ничего не изменится, если вы получаете положительные и отрицательные стороны, когда это необходимо.
Во-вторых, есть разница между вашей собакой и ветчиной. Посмотрите на базу данных после обработки ваших примеров:
?- listing.
⋮
:- dynamic dog/1.
dog(john).
⋮
Где ham/1
? Нигде. Когда ты asserta(dog(john))
Пролог осознает, что dog/1
это предикат, но это никогда не случалось с ham/1
, Таким образом, вы должны решить, правильно ли сформирован этот запрос, и в этом случае вы хотите перехватить исключение или предварительно объявить все возможные предикаты с помощью dynamic/1
или будьте счастливы, что это не правильно сформировано. Ваш сценарий использования определит, что подходит. Например, вы можете просто сделать это:
?- [user].
|: :- dynamic ham/1.
|: % user://2 compiled 0.00 sec, 1 clauses
true.
?- input.
|: Is john a ham
false.
Я сомневаюсь, что вы захотите сделать это для всего, так что вы, вероятно, захотите взглянуть на объект вылова SWI-Пролог. См. Правку внизу этого ответа, чтобы узнать, как с этим справиться.
Кроме того, я бы, возможно, немного переработал DCG, чтобы сделать его более общим и простым:
article --> [a].
article --> [the].
article --> [].
noun(Noun) --> article, [Noun].
statement(Rule) --> noun(Noun), [is], noun(Object), { Rule =.. [Object, Noun] }.
query(Fact) --> ['Is'], noun(Noun), noun(Object), { Fact =.. [Object, Noun]}.
sentence(statement(S)) --> statement(S).
sentence(query(Q)) --> query(Q).
action(statement(S)) :- asserta(S).
action(query(Q)) :- Q.
Кроме того, нет необходимости делать statement1
, Вы можете иметь правило DCG с более чем одним телом; даже если вам нужно два тела, вы можете получить их оба statement/1
структуры, чтобы соответствовать в action/1
; вам, конечно, не нужно размножаться statement1/1
так далеко в остальной части вашего кода.
Последнее замечание, вам не нужно цитировать строчные атомы.:)
В целом, я думаю, что вы делаете довольно хорошую работу здесь! Это сложный материал для изучения, а материалы в Интернете довольно редки. Я надеюсь, что вы продолжаете в том же духе, вы, вероятно, начинаете видеть классные вещи, которые вы можете делать с Прологом и DCG!
Изменить: Вы можете поймать ошибку и обработать ее должным образом, заменив последний action/1
пункт с этим:
action(query(Q)) :-
catch((Q -> write(yes) ; write(unknown)),
error(existence_error(procedure, _), _),
write(unknown)),
nl.