Search code examples
prologdcg

Prolog simple program


I am writing a little Prolog program, which is expected to do something as following:

?-input([allan,is,a,name]).
 true.
?-input([Is,allan,a,name]).
 true.

and here is my code:

% Simple answering agent

input(Text) :-
phrase(sentence(S), Text), 
perform(S).

sentence(statement(S)) --> statement(S).

sentence(query(Q))     --> query(Q).

statement(Statement) --> 
    [Thing, 'is', 'a', Category],
    { Statement =.. [Category, Thing]}.

query(Query) --> 
   ['Is', Thing, 'a', Category],
   { Query =.. [Category, Thing]}.

perform(statement(S)) :- asserta(S).

perform(query(Q))     :- Q.

the input([allan,is,a,name]). part seems working fine, but there is a trouble with the query part, for which if I type in input([Is,allan,a,name])., it prints

Is = 'Is'

Can someone please take a look at this problem for me, thank you.


Solution

  • Well, the problem is that Is is a variable and thus prolog instantiates it (with 'Is'). It would be good practise to ensure that all the members of the list are atoms but for a quick fix you could just do:

    query(Query) --> 
    [_, Thing, 'a', Category],
    { Query =.. [Category, Thing]}.
    

    this way, Is won't get instantiated and prolog will just say true. The only problem is that a statement could be interpreted as a query:

    9 ?- input([allan, is, a, name]).
    true ;                                   
    false.                                   
    
    10 ?- input([is, is, a, name]).       
    true .                                   
    
    11 ?- input([allan, is, a, name]).       
    true ;                                   
    true.
    

    which can be fixed with some cuts (or be saying that Thing should be different than 'is' - if that's acceptable)

    Edit: for a more general solution: it really depends on what kind of sentences you want to parse and what compromises the user can make. For example, it might be possible to ask him to give you words that are prolog atoms; if a word that starts with an upper case letter is requested he will have to use ''. Otherwise, it will be better to just give them in a string/atom ('Is allan a name' or "Is allan a name"). It's easy to separate it to individual atoms: use atomic_list_concat/3. For what is allan you still don't need to do something special; it's a 3 word sentence while the rest were 4 so you can separate it immediately.