Read input in prolog and print result

亡梦爱人 提交于 2019-12-01 01:33:02
Daniel Lyons

Just because I enjoy them, I'd be inclined towards a definite clause grammar (DCG). Then you can make statements and parse them fairly easily:

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

The trick going on here with DCGs is that your grammar is being transformed to a difference list representation. The part in brackets is normal Prolog code; the part around it is interpreted either as literal parts of the list or as other grammar rules. So [Word] is matching one atom. We could actually write the rule like this:

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

and it would have the same effect, and perhaps be more readable, but I like being pedantic. Note especially the use of =.., which converts lists into facts and vice versa (so [fruit, apple] becomes fruit(apple)).

Parsing with DCGs is quite easy: use phrase/2:

?- phrase(statement(X), [apple,is,fruit]).
X = fruit(apple).

Then you can use asserta to insert these clauses into the dynamic store:

input(Text) :- 
    phrase(statement(Statement), Text),
    asserta(Statement).

For example:

?- input([apple,is,fruit]).
true.

?- fruit(X).
X = apple.

Now you can write another clause for parsing queries:

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

Looks very similar! And again, if you wanted, you could use this syntax:

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

Now you might want to write a clause to combine both grammar rules into one "sentence" rule:

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

Try it out:

?- phrase(sentence(X), ['Is', apple, fruit]).
X = query(fruit(apple)).

?- phrase(sentence(X), [apple, 'is', fruit]).
X = statement(fruit(apple)) ;

You see now we get not just the parsed fact, but also a wrapper that tells us whether it was a statement or a query. We can now parse with this instead of statement and query, and rewrite input like so:

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

I've added an auxiliary to handle the work:

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

This will be convenient later as you add more grammatical abstractions: each perform clause handles a different "sentence" type, so you do your parsing above and handle the work below. And now we have, more or less, what you wanted:

?- input([apple,is,fruit]).
true ;
false.

?- input(['Is',apple,fruit]).
true.

?- input(['Is',banana,fruit]).
false.

You can improve things by introducing a cut in your sentence rule and handling true/false with special output, but I think this is the direction I'd want to go in, particularly if you want to be able to handle different syntax in the future.

You are not using Prolog syntax. What you describe could be implemented in this way (untested code):

:- dynamic facts/1.

input(L) :-
  (  L == [is|_]
  -> (  facts(L)
     -> true
     ;  get_kind(L, K), format('no, it is ~w~n', [K])
     )
  ;  assert(facts(L))  % should check duplicates?
  ).

get_kind([is, Object, _], Kind) :-
  facts([Object, is, Kind]) -> true ; Kind = unknow.

Beware to symbols starting with Uppercase: these are Variables, not atoms.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!