Search code examples
databaseprologdcg

How would I create a DCG to parse queries about a database?


I'm just playing around with learning Prolog and am trying to build a database of information and then use natural English to query about relationships. How would I go about doing this?

Example:

%facts

male(bob).
female(sarah).
male(timmy).
female(mandy).

parent(bob, timmy).
parent(bob, mandy).
parent(sarah, timmy).
parent(sarah, mandy).

spouse(bob, sarah).
spouse(sarah, bob).

%some basic rules

married(X,Y) :- spouse(X,Y).
married(X,Y) :- spouse(Y,X).

child(C,X) :- parent(X,C).

Now, I want to ask some "who" questions, i.e., "who is the parent of timmy".

I read something about DCGs, but, can anyone point me to some good resources or get me going in the right direction?

Thank you!


Solution

  • First, I would also like to ask a "who" question: In a fact like

    parent(X, Y).
    

    WHO is actually the parent? Is it X or is it Y?

    To make this clearer, I strongly recommend you use a naming convention that makes clear what each argument means. For example:

    parent_child(X, Y).
    

    Now, to translate "informal" questions to Prolog goals that reason over your data, consider for example the following DCG:

    question(Query, Person) --> [who,is], question_(Query, Person).
    
    question_(parent_child(Parent,Child), Parent) --> [the,parent,of,Child].
    question_(parent_child(Parent,Child), Child)  --> [the,child,of,Parent].
    question_(married(Person0,Person), Person)    --> [married,to,Person0].
    question_(spouse(Person0,Person), Person)     --> [the,spouse,of,Person0].
    

    Here, I am assuming you have already converted given sentences to tokens, which I represent as Prolog atoms.

    In order to conveniently work with DCGs, I strongly recommend the following declaration:

    :- set_prolog_flag(double_quotes, chars).
    

    This lets you write for example:

    ?- Xs = "abc".
    Xs = [a, b, c].
    

    Thus, it becomes very convenient to work with such programs. I leave converting such lists of characters to tokens as an exercise for you.

    Once you have such tokens, you can use the DCG to relate lists of such tokens to Prolog queries over your program.

    For example:

    ?- phrase(question(Query, Person), [who,is,the,parent,of,timmy]).
    Query = parent_child(Person, timmy) .
    

    Another example:

    ?- phrase(question(Query, Person), [who,is,the,spouse,of,sarah]).
    Query = spouse(sarah, Person).
    

    To actually run such queries, simply post them as goals. For example:

    ?- phrase(question(Query, Person), [who,is,married,to,bob]),
       Query.
    Query = married(bob, sarah),
    Person = sarah .
    

    This shows that such a conversion is quite straight-forward in Prolog.

    As @GuyCoder already mentioned in the comments, make sure to check out for more information about DCG notation!