Using Prolog's dcg-notation:
:- set_prolog_flag(double_quotes, chars).
:- use_module(library(double_quotes)). % SWI, SICStus only
monlangage --> "ab" | "a", monlangage.
?- phrase(monlangage,L).
L = "ab"
; L = "aab"
; L = "aaab"
; L = "aaaab"
; L = "aaaaab"
; ... .
See this how to get such compact answers (default in Scryer and Trealla). Otherwise, you get answers like L = [a,a,a,b]
etc.
To get some practice with Definite Clause Grammars it helps to reformulate the grammar a couple of times. For example, there is some redundancy to be identified:
monlangage --> "ab" | "a", monlangage.
% ^ ^
Both alternatives start with "a"
!
monlangage_bis --> "a", ( "b" | monlangage_bis ).
?- phrase(monlangage_bis,L).
L = "ab"
; L = "aab"
; L = "aaab"
; L = "aaaab"
; L = "aaaaab"
; ... .
Now, are these languages really the same? Is above query sufficient to ensure this? Well consider
sonlangage --> "ab" | "a", sonlangage | "b". % règle provocateur !
?- phrase(sonlangage,L).
L = "ab"
; L = "aab"
; L = "aaab"
; L = "aaaab"
; L = "aaaaab"
; ... .
Looks pretty much the same, yet,
?- phrase(monlangage, "b").
false.
?- phrase(sonlangage, "b").
true. % unexpected
How can we identify such differences quickly? Inspecting the set of solutions as above did not help. The real problem behind was that Prolog enumerated the solutions in an unfair manner.
What we can do is to enumerate all solutions/answers by length.
?- length(L,_), phrase(monlangage, L).
L = "ab"
; L = "aab"
; L = "aaab"
; L = "aaaab"
; ... .
?- length(L,_), phrase(sonlangage, L).
L = "b" % caught!
; L = "ab"
; L = "ab" % redundant (but not incorrect)
; L = "aab"
; L = "aab" % idem
; ... .
This will not find all the errors, but at least we can ensure that there are no differences up to a certain finite length.
Another way to reformulate monlangage//0
would be to better outline that all sentences end with "b".
monlangage_ter --> "a", as, "b".
as --> "" | "a", as.
Or in a more generic fashion:
monlangage_quater --> "a", star("a"), "b".
star(NT__0) --> "" | NT__0, star(NT__0).