Start by asking about all possible sentences. You could, for example take the most general query:
?- phrase(s,L).
L = [a, b] ;
L = [a, a, b, b] ;
L = [a, a, a, b, b, b] ; % this is your example
L = [a, a, a, a, b, b, b, b] ...
In general, however, this method might enumerate answers/solutions in an unfair manner ; thereby hiding shorter examples. To ensure that you will find all solutions ordered by length:
?- length(L,N), phrase(s,L).
In this case, there is no difference. But think of adding the rule symbol(0,_) --> [].
after all the other rules. L = []
would not show in the first query, it is "hidden by infinitely many solutions", but it would show as first solution in the second one.
So before trying to understand the more complex example you gave, consider [a, b]
since it is the simplest example.
Another approach is to dissect the query phrase(s, L)
and consider each of its constituents:
?- phrase(symbols(Sem,a),L).
Sem = s(0),
L = [a] ;
Sem = s(s(0)),
L = [a, a] ;
Sem = s(s(s(0))),
L = [a, a, a]
So this part plus the same with b
describes the entire sentence.