Read input in prolog and print result

不羁的心 提交于 2019-12-03 23:05:24

问题


I am learning Prolog ideas and here is what I want to practice:

I want to write a Prolog program that can work like this:

?- input([apple,is,fruit]).
?- input([chicken,is,meat]).
?- input([Is,apple,meat]).
No, it is a fruit
?- input[(Is,chicken,meat])
Yes.

And when I was trying to implement this program, I got some problem:

(1) I used this code trying to read the input and distinguish between questions and assertions, but it fails:

input([]).
input([X|R]) :- X is 'Is', write('test code read question'); write("test code read assertion").

(2) I am still confused about How I can filter the useful information out from the input message. For example, in the [Apple,is,fruit]input array, all I need is apple and fruit. How do we normally do to jump the is word?

I don't want to hardcode too many things to the program, and prefer a good functional programming style to solve the problem that can help me learn from it.

Thank you in advance.


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/12733874/read-input-in-prolog-and-print-result

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