1

I'm trying to write some dcg grammar in prolog which will describe language of
a^nb^n n>=0
"",ab,aabb,aaabbb itd

All what I wrote is

s --> slowo.
slowo --> [a],slowo,[b],!.
slowo --> [].  

And its good as long as all I want to do is just check if word is correct, but how should dcg grammar look in prolog for ?-phrase(s,X) which will generate all words from my language?

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
whd
  • 1,819
  • 1
  • 21
  • 52

3 Answers3

5

In addition to @Mog's answer, let us consider the more general case:

What, if the grammar is so complex, that reordering DCG-rules will not help? How can we still enumerate all sentences? If the grammar is formulated in such a manner, that it terminates for a fixed length, we get all sentences with

?- length(Xs, N), phrase(s, Xs).

The goal length alone will enumerate all lists in a fair manner. That is, starting with the shortest [] all lists are enumerated:

?- length(Xs, N).
   Xs = [], N = 0
;  Xs = [_A], N = 1
;  Xs = [_A,_B], N = 2
;  Xs = [_A,_B,_C], N = 3
;  Xs = [_A,_B,_C,_D], N = 4
;  ... .

And now, the length being fixed, the goal phrase(s, Xs) will find all answers for that fixed length. As an example, look at Mat's answer to this grammar.

So this is a general method to inspect a grammar's sentences. However - there is a price to pay for this generality! For grammars with finitely many sentences, out method will not terminate:

:- use_module(library(double_quotes)).

s --> "a"|"b".

?- phrase(s, Xs).
   Xs = "a"
;  Xs = "b".

This grammar works out of the box, but together with length/2 we get now:

?- length(Xs, N),phrase(s, Xs).
   Xs = "a", N = 1
;  Xs = "b", N = 1
;  loops.

This method is often called iterative deepening, although this term more precisely imposes a bound to the depth of the derivation. But we are imposing a bound to the actual "output". So iterative deepening is also able to handle left-recursion, whereas length/2 works only for grammars that terminate for a fixed input length.

What makes this technique so particularly interesting in Prolog is that it meshes perfectly with Prolog's chronological backtracking mechanism.

false
  • 10,264
  • 13
  • 101
  • 209
  • specifying the length of the list passed to phrase/2 is great! I wasn't aware that this could be done. Obviously, this is perfect for generating all lists of a set length! – sail0r May 13 '21 at 15:33
3

If you're beginning with Prolog, try to avoid the use of !/0. You can generally do better without it.

Here for example, your grammar could be written as follows:

s --> [].
s --> [a], s, [b].

and queried as follows:

?- phrase(s, X).

Note that prolog clauses are picked from left to right and top to bottom, so a rule written at the top of another one will be prioritized when the backtracking is involved.

m09
  • 7,490
  • 3
  • 31
  • 58
  • Thanks it works but is it possible to make s deterministic (without backtracking) when its checking the word and it still can generate all words – whd Mar 25 '12 at 22:47
  • you can use `once/1` if needed : `once(phrase(s, ['a', 'b'])).` or go with `phrase((s, {!}), ['a', 'b']).` or some thing of the sort. But learning to tolerate the `;fail` is an interesting way to solve the problem too :p – m09 Mar 25 '12 at 22:56
  • how to use fail in dcg ? as its fail/0 not fail/2? – whd Mar 26 '12 at 05:34
  • how do you want to use it? Post a code sample in your question! – m09 Mar 26 '12 at 05:43
2

In SWI Prolog, I could use:

s(X, []).

or

phrase(s, X).

(as you suggested) to get all of the strings. In order for that to produce any answers without a stack overflow, however, I needed to reverse the order of the two rules for slowo and remove the cut from the recursive rule.

Jeremiah Willcock
  • 30,161
  • 7
  • 76
  • 78