В дополнение к ответу @firefrorefiddle я бы хотел отметить три вещи.Во-первых, при использовании чисел Пеано более привычно использовать функтор s / 1 для обозначения преемника и одну букву, такую как X, для переменной, таким образом получая меньшие члены:
s(X) succ(Count)
s(s(X)) succ(succ(Count))
s(s(s(X))) succ(succ(succ(Count)))
s(s(s(s(X)))) succ(succ(succ(succ(Count))))
. .
. .
. .
Во-вторых, для дальнейшегоулучшить читабельность, тогда было бы выгодно выбрать другое имя для DCG, может быть что-то вроде language // 1 вместо s // 1.И в-третьих, вместо написания одних и тех же DCG-правил для a
, b
и c
, вы можете определить более общую DCG, которая позволит вам указать элемент и его номер вхождения в списке.Собрав все это вместе, ваш DCG может выглядеть примерно так:
language(s(s(X))) -->
element_frequency(a,s(s(X))),
element_frequency(b,s(X)),
element_frequency(c,X).
element_frequency(_E,0) -->
[].
element_frequency(E,s(X)) -->
[E],
element_frequency(E,X).
В приведенном выше языке кода // 1 соответствует s // 1 в вашем коде, а element_frequency // 2 является заменой для // 1, b // 1 и c // 1.Если вы сделаете запрос к этой DCG, вы обнаружите, что она по-прежнему выдает те же ответы, что и в посте @ firefrorefiddle, например:
?- phrase(language(s(s(s(0)))),L).
L = [a,a,a,b,b,c]