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.
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.
来源:https://stackoverflow.com/questions/12733874/read-input-in-prolog-and-print-result