Пролог - понимание использования разреза
Я не могу ясно понять использование разреза. Например, в этом случае: сгладить, это действительно нужно? Это работает для меня даже без обоих предикатов вырезать (я пытался удалить). В каких случаях обратный ход может привести к сокращению? Снятие разрезов у вас имеет ту же реализацию книги "Искусство пролога" (Шапиро Э., Стерлинг Л.), которая:
flatten([X|Xs],Ys) :-
flatten(X,Ysl),
flatten(Xs,Ys2),
append(Ys1,Ys2,Ys).
flatten(X,[X]) :-
constant(X),
X\=[].
flatten([],[]).
что приводит меня к другому вопросу: необходимо ли во втором пункте проверять, не является ли это списком? Если это единственный термин, не объединится с первым предложением... не так ли?
1 ответ
Программа, связанная в вашем вопросе, использует cut !
оператор для предотвращения объединения кода в ответе с другими пунктами. Без этих порезов flatten2/2
из ответа объединим пустой список по первому аргументу с пунктами один и три, т.е.
flatten2([], []) :- !.
flatten2(L, [L]).
Аналогично, без выреза во втором пункте flatten2/2
объединит непустой список в пунктах два и три, что приведет к некорректному поведению.
Ваш код, с другой стороны, имеет явные проверки, чтобы гарантировать, что каждый пункт flatten/2
имеет дело с одной конкретной ситуацией:
- Первое предложение рекурсивно сглаживает непустые списки
- Второе предложение создает список из одного элемента из констант, отличных от пустых списков
- Третий пункт "выравнивает" пустые списки.
Поскольку каждый пункт применяется исключительно к одному типу элементов слева, вырезать не нужно. Вы могли бы переписать свой код с вырезкой, переключив второе и третье предложение и добавив вырезку после сопоставления с пустым списком, но я настоятельно рекомендую не делать этого ( демонстрация).
нужно ли во втором пункте проверять, не является ли это списком?
Эта проверка необходима, потому что пустой список []
считается константой, поэтому ваша программа будет иметь некорректное поведение, когда пустые списки присутствуют в выравниваемом списке ( демо).