MrLowbob
MrLowbob

Reputation: 102

Prolog: generate queries out of DCG

I currently have a small Prolog database containing a few people and some predicates for relations. For example:

female(anna).
female(susan).

male(john).
male(timmy).

siblings(anna, susan).
siblings(anna, john).
siblings(susan, john).

sibling(X, Y) :- siblings(X, Y) ; siblings(Y, X).

%X is brother of Y
brother(X, Y) :- male(X), sibling(X, Y).

and I have a DCG which can determine valid questions like "who is the brother of john", which also works well.

question --> ip, verb, article, noun, pronoun, name.

Now I want my program to make a call to my family-database out of noun and name like this:

noun(X, name).

Which in the example then should be

brother(X, anna).

and then return the answer as a natural-language answer like:

"the brother of anna is john"

Defining the grammer for the answer sentence is no problem either. The only thing I don't know is, how to make the call from my DCG to my database and to get the right values filled into it. I looked around for quite some time now - perhaps I don't know the right search terms - and couldnt find something related to this.

I hope you guys have some good ideas ! :)

Thank you.

Upvotes: 4

Views: 434

Answers (1)

mat
mat

Reputation: 40768

Invoking Prolog predicates from DCGs

Regular way: Use {}/1

Use the nonterminal {}//1 to call arbitrary Prolog goals from within DCGs.

For example:

verb --> [V], { verb(V) }.

This defines a nonterminal verb//1. This DCG describes a list consisting of the element V such that verb(V) holds, where verb/1 is a normal Prolog predicate.

In a sense even more regular: Use DCGs throughout!

Note that there is a second way to do this, which is in a sense even easier to understand: You can simply turn everything into DCG nonterminals!

For example, you could say:

female(anna)  --> [].
female(susan) --> [].
male(john)    --> [].
male(timmy)   --> [].

You could then simply use these nonterminals directly. You could define a term_expansion/2 rule that does such a transformation automatically.

In your specific case, using {}/1 is likely preferable, because you already have existing Prolog facts and. But there are definitely cases where using DCGs throughout is preferable.

EDIT: From your comment, I see your question is a bit more involved.

The question is rather about:

Constructing Prolog goals from sentences

This is extremely straight-forward: Essentially, you only need to describe the relation between the Prolog goals you want and the corresponding sentences.

We do this by introducing a new argument to the DCG, and that argument will denote the Prolog goal that needs to be executed to answer the sentence. In your example, you want to relate the sentence "Who is the brother of susan?", to a call of the Prolog predicate brother(X, susan). You already have a nonterminal sentence//0 that describes such sentences. You only need to make explicit the goal that such sentences correspond to. For example:

sentence_goal(noun(X, name)) --> ip, v, a, noun, p, name.

This is only used to illustrate the principle; I'm not claiming that this is already the full solution. The point is simply to show that you can reason about Prolog goals in exactly the same way as about all other terms.

You can then invoke the actual goals in two phases:

  1. first, relate the given sentence to the goal, using this new nonterminal sentence_goal//1
  2. simply call the goal, using call/1 or invoking it directly.

For example:

?- phrase(sentence_goal(Goal), Sentence), Goal.

In your case, all that remains is relating such sentences to the Prolog goals you want to invoke, such as brother_of/2 etc.

None of this needs any side-effects (write/1)! Instead, concentrate on describing the relations between sentences and goals, and let the Prolog toplevel do the printing for you.

Upvotes: 5

Related Questions