Во-первых, как уже указывалось @lurker в комментариях, всегда используйте phrase/2
или phrase/3
при вызове DCG. Во-вторых, как указывают @TomasBy и @WillBeason, ваш DCG описывает список, содержащий атомы x
, y
и z
, разделенные запятыми. Итак, чтобы проверить, является ли xz действительным предложением (я полагаю, это то, что означает s
) в соответствии с вашей грамматикой, вы должны запросить:
?- phrase(s,[x,z]).
true ;
false.
Действительно, это так. Теперь давайте посмотрим на самый общий запрос, то есть спросим Какие предложения есть? :
?- phrase(s,S).
ERROR: Out of local stack
Это не очень хорошо. Причиной этого является порядок правил DCG: вызов s//0
приводит к вызову первого правила e//0
, которое рекурсивно вызывает e//0
, то есть первое правило e//0
и т. Д. цикл продолжается до тех пор, пока Пролог не выйдет из стека. Итак, давайте изменим порядок правил, поместив сначала нерекурсивное правило ...
s --> e.
e --> [z]. % <- moved here from last position
e --> [x], e.
e --> [y], e.
... и повторите запрос:
?- phrase(s,S).
S = [z] ;
S = [x, z] ;
S = [x, x, z] ;
S = [x, x, x, z] ;
.
.
.
Теперь мы получаем актуальные решения. Так что порядок правил DCG имеет значение . Однако перечисление ответов является несправедливым, поскольку последнее правило e//0
, которое относится к y
, фактически никогда не вызывается. Это можно исправить, поставив перед собой цель length/2
. Запрос ...
?- length(S,_).
S = [] ;
S = [_G3671] ;
S = [_G3671, _G3674] ;
S = [_G3671, _G3674, _G3677] ;
.
.
.
... возвращает списки со всеми возможными длинами, поэтому добавление префикса к вызову DCG заставит Prolog найти все решения длины 0, прежде чем перейти к длине 1, а затем перейти к длине 2 и т. Д. ...
?- length(S,_), phrase(s,S).
S = [z] ; % <- solutions of length 1 from here
S = [x, z] ; % <- solutions of length 2 from here
S = [y, z] ;
S = [x, x, z] ; % <- solutions of length 3 from here
S = [x, y, z] ;
S = [y, x, z] ;
S = [y, y, z] ;
S = [x, x, x, z] ; % <- solutions of length 4 from here
.
.
.
Таким образом, ваша грамматика фактически производит предложения произвольной длины, как и должно быть. Переходя к примеру с семью предложениями, если ваше приложение требует ограничения длины списков, вы можете сделать это, поставив перед вашим запросом цель between/3
...
?- between(1,3,N), length(S,N), phrase(s,S).
N = 1,
S = [z] ;
N = 2,
S = [x, z] ;
N = 2,
S = [y, z] ;
N = 3,
S = [x, x, z] ;
N = 3,
S = [x, y, z] ;
N = 3,
S = [y, x, z] ;
N = 3,
S = [y, y, z] ;
false.
... теперь получится все семь предложений, состоящих не более чем из 3 слов Обратите внимание, что ваш пример {xz, xy , xyz, xyxz , z, xxyz , xyz } не совсем набор предложений описывается вашей грамматикой. Элемент xy не является предложением вообще согласно правилам грамматики. Предложения xyxz и xxyz определяются вашей грамматикой, но требуют максимальной длины не менее четырех слов, что даст шестнадцать ответов. И последнее из семи предложений, xyz , появляется дважды в вашем примере, если вы не имели в виду запрос ...
?- phrase(s,[X,y,z]).
X = x ;
X = y ;
false.
... с двумя предложениями, первое из которых по-прежнему является дубликатом.
Наконец, если вам действительно необходимо получить атомы в качестве ответа, вы можете изменить DCG, чтобы поместить в список коды, соответствующие x
, y
и z
, вместо реальных атомов. Затем вы можете использовать atom_codes/2
, чтобы получить предложения как один атом вместо списка слов:
s --> e.
e --> [0'z]. % 0'z denotes the code corresponding to z
e --> [0'x], e. % 0'x denotes the code corresponding to x
e --> [0'y], e. % 0'y denotes the code corresponding to y
?- between(1,3,N), length(S,N), phrase(s,S), atom_codes(A,S).
N = 1,
S = [122],
A = z ;
N = 2,
S = [120, 122],
A = xz ;
N = 2,
S = [121, 122],
A = yz ;
N = 3,
S = [120, 120, 122],
A = xxz ;
N = 3,
S = [120, 121, 122],
A = xyz ;
N = 3,
S = [121, 120, 122],
A = yxz ;
N = 3,
S = [121, 121, 122],
A = yyz ;
false.