问题
Given a CFG
S --> a S b | c | d
I wanna write a predicate like, grammar('S', sentence) which generates all possible
sentences like
sentence=acb,
sentence=acd,
sentence=c,
sentence=ab......................
Using left most derivation, if the encountered symbol is terminal it should print out that terminal, and if the encountered symbol is non terminal 'S', it should backtrack and substitute and one of the grammar a S b or c or d and repeat the process.
I dont want any code...just help me with some tips how to start with
回答1:
Let's use DCGs to encode your grammar literally!
s --> [a], s, [b] | [c] | [d].
?- phrase(s,Xs).
ERROR: Out of local stack
Seems that this query does not terminate. I.e. Prolog's very simple execution strategy did not find a solution. On the other hand, think of it: Your grammar describes an infinite set of sentences. If you are enumerating an infinite set it is easy to start "at the wrong end". That's what Prolog actually does here.
But things are not that bad at all. What about enumerating all sentences of a fixed length. I will try 5:
?- length(Xs,5), phrase(s,Xs).
Xs = "aacbb" ;
Xs = "aadbb" ;
false.
In this case, all sentences are found and Prolog even assures us that there are no further sentences.
?- length(Xs,4), phrase(s,Xs).
false.
There are no sentences of length 4.
We can now enumerate all sentences, by length.
?- length(Xs,N), phrase(s,Xs).
Xs = "c",
N = 1 ;
Xs = "d",
N = 1 ;
Xs = "acb",
N = 3 ;
Xs = "adb",
N = 3 ;
Xs = "aacbb",
N = 5 ;
Xs = "aadbb",
N = 5 ;
Xs = "aaacbbb",
N = 7
What kind of derivation did we use here? Honestly, I don't know and I don't care. What is important to know is when Prolog will terminate. In this case, it will terminate, if the length is known. And that is all we need to know to guarantee that we have a fair enumeration of the infinite set. Things are even slightly better: s//0
will also terminate in cases where the length is not known like
?- Xs = [a,a,b|_], phrase(s,Xs).
false.
?- Xs = [a,a,c|_], phrase(s,Xs).
Xs = "aacbb" ;
false.
?- dif(X,Y), Xs = [X,Y|_], phrase(s,Xs).
X = a,
Y = c,
Xs = "acb" ;
X = a,
Y = d,
Xs = "adb" ;
false.
Edit: I got some questions about the toplevel answers using "acb"
for a list [a,c,b]
: Please refer to this answer for an explanation and to library(double_quotes).
来源:https://stackoverflow.com/questions/8332100/handling-prolog-context-free-grammar