I use swiprolog and have a knowlegdebase with some facts like:
det(the).
det(a).
adjective(quick).
adjective(brown).
noun(cat).
noun(fox).
prep(on).
prep(with).
verb(sat).
verb(ran).
and I have a rule
generate_grammar(GrammarList):-
new_rule(GrammarList).
This rule gets passed a list with an unknown number of elements e.g. [det,noun,verb,prep]
and should generate a new rule for the passed "grammar". The new rule should generate a "sentence" with the given facts and the new grammar. I tested some things but I didn´t get it worked.
I think the desired rule looks something like:
new_rule(List) :-
Head=sentence(X),
Body=[List]
dynamic(Head),
assertz(Head :- Body).
I have no idea how to do this right. So how could this be done?
Thanks in advance!
While it probably is possible to add rules to the store dynamically using assertz/1
et. al. I have never really had to do it, because it's too easy to get Prolog to evaluate other data structures.
For your particular database, all your facts have arity 1, so we can just use call/2
to evaluate them:
?- call(det, D).
D = the ;
D = a.
Leveraging this, you can solve the problem using maplist/2
without any actual intermediate structures:
sentence(Grammar, Words) :- maplist(call, Grammar, Words).
Using it:
?- maplist(call, [det,adjective,noun,verb], Sentence).
Sentence = [the, quick, cat, sat] ;
Sentence = [the, quick, cat, ran] ;
Sentence = [the, quick, fox, sat] ;
Sentence = [the, quick, fox, ran] ;
Sentence = [the, brown, cat, sat] ;
Sentence = [the, brown, cat, ran] ;
Sentence = [the, brown, fox, sat] ;
Sentence = [the, brown, fox, ran] ;
Sentence = [a, quick, cat, sat] ;
Sentence = [a, quick, cat, ran] ;
Sentence = [a, quick, fox, sat] ;
Sentence = [a, quick, fox, ran] ;
Sentence = [a, brown, cat, sat] ;
Sentence = [a, brown, cat, ran] ;
Sentence = [a, brown, fox, sat] ;
Sentence = [a, brown, fox, ran].
You can actually turn this into a true relation by adding facts for the known syntactic categories:
category(det).
category(adjective).
category(noun).
category(prep).
category(verb).
Then you can describe a relation between categories and words that belong to those categories:
cat_word(C,W) :-
category(C),
call(C,W).
?- cat_word(C,W).
C = det,
W = the ;
C = det,
W = a ;
C = adjective,
W = quick ;
C = adjective,
W = brown .
.
.
.
Finally, following the idea presented by @Daniel Lyons, you can apply maplist/3 to cat_word/2:
grammar_sentence(G,S) :-
maplist(cat_word,G,S).
In the grammar to sentence direction this yields the same results as Daniels predicate sentence/2:
?- grammar_sentence([det,adjective,noun,verb],S).
S = [the, quick, cat, sat] ;
S = [the, quick, cat, ran] ;
S = [the, quick, fox, sat] ;
S = [the, quick, fox, ran] ;
S = [the, brown, cat, sat] ;
S = [the, brown, cat, ran] ;
S = [the, brown, fox, sat] ;
S = [the, brown, fox, ran] ;
S = [a, quick, cat, sat] ;
S = [a, quick, cat, ran] ;
S = [a, quick, fox, sat] ;
S = [a, quick, fox, ran] ;
S = [a, brown, cat, sat] ;
S = [a, brown, cat, ran] ;
S = [a, brown, fox, sat] ;
S = [a, brown, fox, ran].
But grammar_sentence/2 can also be used in the sentence to grammar direction:
?- grammar_sentence(G,[the,quick,cat,sat]).
G = [det, adjective, noun, verb] ;
false.
?- grammar_sentence(G,[the,cat,sat]).
G = [det, noun, verb] ;
false.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With