@ Ответ Junuxx - это один шаг к решению; есть и другая проблема в вашей программе. Но первый шаг назад: @Junuxx заметил проблему и исправил ее. Ницца. Но как может вы пятно такая проблема? На самом деле, вы спросили »бесконечный цикл – но как?«
Что прохладно в Прологе является то, что часто можно локализовать циклическую программу до очень маленького фрагмента программы. Такой фрагмент называется failure-slice. То есть: больше нет глазных язв, читающих длинные программы!
Вернемся к вашей программе. Если вы загружаете его, вы получите такое сообщение:
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
: Никто не заботится об этом, он просто «сдал». Только первый и третий аргументы могут гарантировать прекращение действия!
Подробнее см. Ярлык failure-slice.
мелкий шрифт
Некоторые ограничения! Пустота, где запрещено! Вы можете сделать выше рассуждения только с чистой, монотонной программой Prolog. На самом деле, некоторые доброкачественные побочные эффекты, как те, которые у вас есть в вашей программе, тоже в порядке. Пока они не влияют на поток управления.
Другая проблема
Существует еще одна проблема с вашей программой. Запустите printSentence([you]), false
, чтобы посмотреть! Откат и побочные эффекты не собираются легко. Для начинающих лучше всего избегать побочных эффектов. См., Например, this question и that answer, как удалить бесполезные побочные эффекты при программировании. Почему бы не позвонить по номеру transform([you, are, my, only hope], Xs)
или maplist(replace,[you, are, my only, hope], Xs)
? Это позволяет вам снова сосредоточиться на соответствующих частях!
Что вы попытались исправить? Каков желаемый эффект предиката преобразования? – Junuxx