В дополнение к ответу @ Mog, давайте рассмотрим более общий случай:
Что, если грамматика настолько сложна, что переупорядочение DCG-правил не поможет? Как мы можем еще перечислить все предложения? Если грамматика сформулирована таким образом, что она заканчивается на фиксированную длину, мы получаем все предложения с
?- <b>length(Xs, N), phrase(s, Xs).</b>
Цель length
сама перечислит все списки справедливым образом. То есть, начиная с самого короткого []
, перечисляются все списки:
?- <b>length(Xs, N).</b>
Xs = [],
N = 0 ;
Xs = [_G307],
N = 1 ;
Xs = [_G307, _G310],
N = 2 ;
Xs = [_G307, _G310, _G313],
N = 3 ;
Xs = [_G307, _G310, _G313, _G316],
N = 4 ; ...
И теперь, когда длина фиксирована, цель phrase(s, Xs)
найдет все ответы для этой фиксированной длины. Как пример, посмотрите на ответ Мата на эту грамматику .
Так что это общий метод проверки предложений грамматики. Однако за эту общность есть цена! Для грамматик с конечным числом предложений метод out не завершается:
:- use_module(
library(double_quotes)
).
s --> "a"|"b".
?- <b>phrase(s, Xs).</b>
Xs = "a" ;
Xs = "b".
Эта грамматика работает из коробки, но вместе с length/2
мы получаем сейчас:
?- <b>length(Xs, N),phrase(s, Xs).</b>
Xs = "a",
N = 1 ;
Xs = "b",
N = 1 ;
<strong>**loops**</strong>
Этот метод часто называют итеративным углублением , хотя этот термин более точно накладывает ограничение на глубину дифференцирования. Но мы налагаем границу на фактический «результат». Таким образом, итеративное углубление также может обрабатывать левую рекурсию, тогда как length/2
работает только для грамматик, которые заканчиваются для фиксированной длины ввода.
Что делает эту технику особенно интересной в Прологе, так это то, что она идеально сочетается с хронологическим механизмом обратного отслеживания Пролога.