2016-09-22 3 views
1

Я недавно изучал Пролог, и у меня проблемы с его работой, как я этого хочу. В качестве примера у меня была задана задача создать психиатора Пролога, который вносит свой вклад и превращает его в вопрос: «Я думаю, что я нездоров» становится «Почему вы думаете, что вам нездоровится?».Пролог написать бесконечный цикл

Однако мой код до сих пор генерирует бесконечный цикл, когда он выходит. Он вызывает повтор на printSentence с другой несвязанной переменной, привязав ее к концу списка Output и делая это навсегда.

Вот мой код:

/* printSentence simply calls the in-built Prolog write function. */ 
printSentence([]) :- write('?'). 
printSentence([H|T]) :- write(H),write(' '), printSentence(T). 

answer([], _) :- write('Why are you silent? Talk to me.'). 
answer(Input, Output) :- thinkMatch(Input, Output), printSentence(Output). 

thinkMatch(['I', 'think'|Rest], ['Why', 'do', 'you', 'think'|SwitchedRest]) :- switchPronouns(Rest, SwitchedRest). 

switchPronouns([], _). 
switchPronouns([H|T], [R|SwitchedRest]) :- switchWord(H, R),switchPronouns(T, SwitchedRest). 


switchWord('I', 'you'). 
switchWord('myself', 'yourself'). 
switchWord('am', 'are'). 
switchWord('you', 'me'). 
switchWord('yourself', 'myself'). 
switchWord(H, H). 

вход,

answer(['I', 'think', 'therefore', 'I', 'am'],Output). 

производит эти результаты происходит навсегда,

?- Input = ['I', 'think', 'therefore', 'I', 'am'],answer(Input, Output). 
Why do you think therefore you are ? 
Input = ['I', think, therefore, 'I', am], 
Output = ['Why', do, you, think, therefore, you, are] ; 
_G4395 ? 
Input = ['I', think, therefore, 'I', am], 
Output = ['Why', do, you, think, therefore, you, are, _G4395] ; 
_G4398 ? 
Input = ['I', think, therefore, 'I', am], 
Output = ['Why', do, you, think, therefore, you, are, _G4395, _G4398] ; 
_G4401 ? 
Input = ['I', think, therefore, 'I', am], 
Output = ['Why', do, you, think, therefore, you, are, _G4395, _G4398|...] 

Извинения, если это что-то маленькое и немым Я но чтобы полностью понять внутренние махинации Пролога.

Заранее спасибо.

ответ

2

Вы написали switchPronouns([], _)., что означает, что для пустого ввода выход может быть любым. Конечно, это неправильно; что вы действительно хотите, так это то, что для пустого ввода выходной сигнал также пуст: switchPronouns([], [])..

Причина, по которой идет в бесконечный цикл, потому что это будет в конечном итоге вызова printSentence([H|T]) с uninstantiated переменной для T (когда выходной сигнал может быть «ничего» и Пролог не имеет значения для него все же, она оставляет его uninstantiated). Теперь Prolog пытается сопоставить рекурсивное предложение и видит, что если T - пустой список, то знак вопроса печатается. Это первое найденное решение.

Однако Prolog не знает, действительно ли вы предназначались для него как пустой список, поэтому он также пытается выполнить второе предложение: что, если T - непустой список формы [_H | _T]? В этом случае голова и хвост неизвестны. Таким образом, он печатает неназначенную голову и продолжает рекурсивный вызов с хвостом. Но хвост снова неизвестен! Таким образом, мы оказываемся в бесконечной рекурсии.


Вы заметите, что после обновления switchPronouns, выход еще не правильно. Хотя сейчас существует конечное число ответов, он дает кучу ответов, которые вы не ожидали:

Why do you think therefore you are ? 
Output = ['Why', do, you, think, therefore, you, are] 
Why do you think therefore you am ? 
Output = ['Why', do, you, think, therefore, you, am] 
... 

Причина этого кроется в switchWord. Если, например, входное слово «I», Prolog может сопоставить его с предложением switchWord('I', 'you').. Тем не менее, он также может соответствовать switchWord(H, H).! То, что вы действительно хотите, - это использовать «реальное» совпадение и сохранять слово без изменений, если нет сопоставления.

я бы написать что-то вроде этого:

switchWord (I, O): - word_map (I, R) -> O = R; O = I.

word_map('I', 'you'). 
word_map('myself', 'yourself'). 
word_map('am', 'are'). 
word_map('you', 'me'). 
word_map('yourself', 'myself'). 

И теперь вы получите единственный ожидаемый ответ!


Еще одна небольшая проблема, которую я вижу здесь: answer([], _). Как и выше, это говорит о том, что если вход пуст, выход может быть любым. Вы можете вызвать эту причину всегда не указывают, что это не ответ:

answer([], _) :- write('Why are you silent? Talk to me.'), fail. 

Наконец, как правило, Пролог предикаты записываются в snake_case, не верблюжьего. Это в основном вопрос предпочтения, но использование стандарта делает код более удобным для чтения для других программистов.

+0

Это очень тщательно ответить спасибо большое! Это помогло с моим пониманием того, как работает Prolog – SHolmes

1

Вы можете изменить answer([], _) к answer([], []), а также изменить switchPronouns([], _). к switchPronouns([], []). Причина заключается в том, что матчи с _ ничего: пустой список, список с одним элементом, с two..and идет, так что вы заставить его быть пустой список. И есть еще одна проблема:

?- answer(['I', 'think', 'therefore', 'I', 'am'],Output). 
Why do you think therefore you are ? 
Output = ['Why', do, you, think, therefore, you, are] ; 
Why do you think therefore you am ? 
Output = ['Why', do, you, think, therefore, you, am] ; 
Why do you think therefore I are ? 
Output = ['Why', do, you, think, therefore, 'I', are] ; 
Why do you think therefore I am ? 
Output = ['Why', do, you, think, therefore, 'I', am]. 

Это дает некоторые неправильные ответы из-за switchWord/2. Вы можете изменить также:

answer(Input, Output) :- thinkMatch(Input, Output), printSentence(Output). 

в

answer(Input, Output) :- thinkMatch(Input, Output), printSentence(Output),!. 

, который позволит сократить эти неправильный вывод:

?- answer(['I', 'think', 'therefore', 'I', 'am'],Output). 
Why do you think therefore you are ? 
Output = ['Why', do, you, think, therefore, you, are]. 
+0

О, хорошо, что теперь имеет смысл, благодаря моему мозгу, вчера мой мозг был немного медленным. Я не перебегал через «!» нотация перед тем, что он делает? – SHolmes

+0

Он называется cut, когда пролог пытается доказать предикат, он пытается все возможные решения, cut (!) Оператор разрезает некоторые из возможных решений, если уже нашел решение. Место, где! было поставлено выше, чтобы остановить его, когда он найдет первое правильное решение. Меняем место! вы могли бы управлять, например, два дать два решения и сократить все остальное. Так что это зависит от того, где! размещен... – coder

 Смежные вопросы

  • Нет связанных вопросов^_^