Обрезки в конце рекурсивных предикатов в Прологе
-
20-09-2019 - |
Вопрос
pred(Args).
pred(Args) :-
goalA,
goalB,
!,
pred(Args).
pred(Args) :-
goalC,
goalD,
!,
pred(Args).
Обычно я бы написал рекурсивный предикат, который касался производительности памяти, что-то вроде приведенного выше фрагмента кода.При этом сокращение используется для того, чтобы попытаться принудительно выполнить оптимизацию хвостового вызова.Недавно я просматривал большую базу кода пролога и нашел несколько примеров, в которых вырезание фактически происходит после рекурсивного вызова, а не непосредственно перед ним.Предположительно, это скорее предотвращает оптимизацию хвостовых вызовов, чем помогает ей.
Мой вопрос: могу ли я переместить фрагмент после рекурсивного вызова непосредственно перед ним, не влияя на смысл программы?Это предполагает, что в каждом предложении сказуемого имеется сокращение в одном и том же относительном месте.
Теперь я еще немного об этом подумал, думаю, может быть, ответ «не обязательно», но, переписав весь код с вырезом перед вызовом и обнаружив, что набор тестов все еще проходит, я тоже интересно, может ли быть какая-то другая эзотерическая причина для написания подобных предикатов.Или это просто плохой код?
Решение
Я предполагаю, что это может быть плохое кодирование (или непонимание того, что делал автор).
Я говорю это потому, что сам однажды допустил ту же ошибку:
https://mailbox.iai.uni-bonn.de/mailman/public/swi-prolog/2009/001540.html
http://xonix.habrahabr.ru/blog/60430/ (предупреждение, на русском языке)
Но люди из списка рассылки SWI подтвердили, что правильный вариант кода с хвостовой рекурсией — это
head :-
<guard goals>, !,
<deterministic stuff>,
head.
head :-
...