Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SWI-Prolog rule assertion from passed List

Tags:

prolog

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!

like image 245
74ck Avatar asked Jan 30 '23 09:01

74ck


2 Answers

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].
like image 154
Daniel Lyons Avatar answered Feb 15 '23 19:02

Daniel Lyons


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.
like image 23
tas Avatar answered Feb 15 '23 20:02

tas