2012-06-03 13 views
3

Я не могу понять, где это происходит. Обратите внимание, что я очень новичок в Prolog, и я уверен, что у меня что-то не хватает - просто не знаю, что это может быть. Может ли кто-нибудь помочь мне, пожалуйста?Преобразование предложения создает бесконечный цикл - но как?

Спасибо, вот мой код:

printSentence([]). 
printSentence([W|[]]) :- 
    write(W), 
    write('.'), 
    nl. 
printSentence([W|R]) :- 
    write(W), 
    write(' '), 
    printSentence(R). 

transform([], Result). 
transform([Word|Rest], Result) :- 
    replace(Word, Replacement), 
    append(Result, Replacement, NewResult), 
    transform(Rest, NewResult). 

replace(my, your). 
replace(i, you). 
replace(you, me). 
replace(am, are). 
replace(Word, Word). 

test :- 
    X = [you, are, my, only, hope], 
    transform(X, Result), 
    printSentence(Result). 
+4

Что вы попытались исправить? Каков желаемый эффект предиката преобразования? – Junuxx

ответ

1

Это должно работать. Обратите внимание, что у вас был синглтон в transform([],Result). Кроме того, append не работает так, как вы пытались его использовать, но в целом вы были на правильном пути.

transform([], []). 

transform([Word|Rest], [Replacement|RestOfResult]) :- 
    replace(Word, Replacement), 
    transform(Rest, RestOfResult). 
+0

А это все работает!Подождите, пока я выясню, что на самом деле происходит здесь ... – rtheunissen

+0

Попытка получить мою голову вокруг замены в декларации. – rtheunissen

+0

@ paranoid-android: считать: 'maplist (replace, X, Result)'. И в вашей программе все еще есть серьезная ошибка! – false

6

@ Ответ Junuxx - это один шаг к решению; есть и другая проблема в вашей программе. Но первый шаг назад: @Junuxx заметил проблему и исправил ее. Ницца. Но как может вы пятно такая проблема? На самом деле, вы спросили »бесконечный цикл – но как?«

Что прохладно в Прологе является то, что часто можно локализовать циклическую программу до очень маленького фрагмента программы. Такой фрагмент называется . То есть: больше нет глазных язв, читающих длинные программы!

Вернемся к вашей программе. Если вы загружаете его, вы получите такое сообщение:

 
Warning: /usager/SO/paranoid.pl:13: 
    Singleton variables: [Result] 

, который дает вам уже намек на то, скорее всего, неправильно. Увы, это не ваша самая большая забота на данный момент. Ваша самая большая проблема в том, что цель test петель!

Локализуя незавершение

Так как вы с низким усилием можно понять, что на самом деле цикл?

Один из способов: - запустить индикатор, который покажет вам шаг за шагом, как Prolog выполняет эту программу. Тем не менее, трассировщик покажет вам массу неуместных деталей. Подробно, что вам не нужно понимать при программировании в Prolog. Деталь, которая заполняет ваш разум таким образом, что есть вероятность, что вы полностью упустите реальную проблему. Поэтому, если вы не хотите тратить время на экраны с мельчайшими линиями, держитесь подальше от трассировщиков.

Другой способ: - добавить цели false в вашу программу. Помните, что ваша программа уже петли, поэтому такие дополнительные цели вам не повредят. Зачем уничтожать вашу программу с помощью этих false целей, которые вы никогда не хотели писать в первую очередь? Это потому, что эти цели false помогут вам обнаружить виновника неисполнения в вашей программе, сокрыв «нерелевантные» части. Это так, благодаря следующему замечанию:

Если отказа срезов (= ваш вандализму программа) не оканчивается тогда оригинальная программа не завершается либо.

В некотором смысле, отказ-срез является причиной, по которой ваша программа не заканчивается. Или выразиться сильнее: до тех пор, пока вы не измените видимую часть в отказе; то есть до тех пор, пока вы только пытаетесь удачи, изменяя части, которые не видны в области отказа, проблема будет сохраняться! Гарантированы! Это не самый лучший вид гарантии, но лучше, чем быть слепым.

Вот что я получу как отказ. Я удалил printSentence/1, потому что он больше не используется в фрагменте. И я добавил определение append/3. Некоторые Прологи предлагают append/3 как встроенный предикат, который нельзя изменить. В этом случае используйте другое имя, например local_append/3 – просто не забудьте заменить все вхождения!

append([], Zs, Zs) :- false. 
append([X|Xs], Ys, [X|Zs]) :- 
    append(Xs, Ys, Zs), false. 

transform([], Result) :- false. 
transform([Word|Rest], Result) :- 
    replace(Word, Replacement), 
    append(Result, Replacement, NewResult), false, 
    transform(Rest, NewResult). 

replace(my, your) :- false. 
replace(i, you) :- false. 
replace(you, me). 
replace(am, are) :- false. 
replace(Word, Word) :- false. 

test :- 
    X = [you, are, my, only, hope], 
    transform(X, Result), false, 
    printSentence(Result). 

Когда я загружаю этот отказ-срез, я получаю:

 
?- test. 
ERROR: Out of local stack 

Что является хорошим показателем того, что программа не прекращается. На моем конечном аппаратном уровне он исчерпывает все ресурсы. ((Чтобы быть педантичным, эта программа может по-прежнему заканчиваться, но может потребоваться слишком много ресурсов. Но помните: у нас есть это , если петли отказов, , а затем целые программы. В любом случае, фрагмента отказа часто будет проще, так как фрагмент короче)).

Некоторые наблюдения: Первоначально transform/2 был рекурсивным. Теперь это уже не так. Единственная рекурсия слева находится в пределах append/3. Поэтому я сначала смотрю на цель append(Result, Replacement, NewResult), и я пытаюсь выяснить, какие переменные могут быть. Самый простой из них - 3-й аргумент: NewResult - единственное событие в нашем фрагменте, поэтому мы можем заменить его на _. Переменная второго аргумента Replacement всегда будет me. И первый аргумент (здесь я теперь посмотрю на test/0) будет непроинсталлированной переменной. Поэтому мы должны рассмотреть цель append(_, me, _).

Просто запустите append(_, me, _), false, чтобы увидеть, что эта цель не заканчивается! Вы также можете увидеть это, проверив фрагмент отказа. Вот это, опять-таки:

append([], Zs, Zs) :- false. 
append([X|Xs], Ys, [X|Zs]) :- 
    append(Xs, Ys, Zs), false. 

Посмотрите на Ys: Никто не заботится об этом, он просто «сдал». Только первый и третий аргументы могут гарантировать прекращение действия!

Подробнее см. Ярлык .


мелкий шрифт

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


Другая проблема

Существует еще одна проблема с вашей программой. Запустите printSentence([you]), false, чтобы посмотреть! Откат и побочные эффекты не собираются легко. Для начинающих лучше всего избегать побочных эффектов. См., Например, this question и that answer, как удалить бесполезные побочные эффекты при программировании. Почему бы не позвонить по номеру transform([you, are, my, only hope], Xs) или maplist(replace,[you, are, my only, hope], Xs)? Это позволяет вам снова сосредоточиться на соответствующих частях!