0
input :-
read_line_to_codes(user_input, Input),
string_to_atom(Input,Atoms),
atomic_list_concat(Alist, ' ', Atoms),
phrase(sentence(S), Alist),
action(S).


statement(Rule) --> [Noun, 'is', 'a', Object], { Rule =.. [Object, Noun]}.
statement1(Rule) --> ['A', Noun, 'is', 'a', Object], { Rule =.. [Object, Noun]}.
query(Fact) --> ['Is', Noun, 'a', Object], { Fact =.. [Object, Noun]}.

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


action(statement(S)) :- asserta(S) -> write(ok).
action(statement1(S)) :- asserta(S) -> write(ok).
action(query(Q)) :-( Q -> write(yes); write(unknown)), nl.

The assignment is to create rules from user input in the form " _ is a _." or " A _ is a _." This should respond with "ok".

And then be able to query "Is _ a _?" And respond with "yes" or "unknown". I have no idea why it's giving an error if the predicate(i think that's what it's called, "ham") is not in the database, but its fine with the other part not being in there. Any ideas as to what I'm doing wrong? And sorry if I'm doing something simply stupid, first time with prolog. I'm using SWI-Prolog V.6.2.6 if that matters. And how would I go about omitting the true or false return in the ouput

   11 ?- input.
   |: john is a dog
   ok
   true .

   12 ?- input.
   |: Is john a dog
   yes
   true.


   13 ?- input.
   |: Is abraham a dog
   unknown
   false.

   14 ?- input.
   |: Is john a ham
   ERROR: action/1: Undefined procedure: ham/1
   Exception: (8) ham(john) ? 
false
  • 10,264
  • 13
  • 101
  • 209

1 Answers1

0

First, what Prolog responds with is really an implementation detail. SWI responds "true," but some other implementations respond "ok." There's nothing to change about your code because of that, as long as you're getting affirmatives and negatives when you should.

Second, there is a difference between your dog and ham examples. Look at the database after your sample inputs have been processed:

?- listing.
⋮ 
:- dynamic dog/1.

dog(john).
⋮

Where's ham/1? Nowhere. When you asserta(dog(john)), Prolog becomes aware that dog/1 is a predicate, but that never happened with ham/1. So you have to decide if that query is well-formed, in which case you want to catch the exception or else pre-declare all your possible predicates with dynamic/1, or be happy that it isn't well-formed. Your use scenario will determine which is appropriate. For instance, you could just do this:

?- [user].
|: :- dynamic ham/1.
|: % user://2 compiled 0.00 sec, 1 clauses
true.

?- input.
|: Is john a ham
false.

I doubt you'll want to do that for everything, so you'll probably want to look at SWI-Prolog's catch facility. See the edit at the bottom of this answer for an example of how to handle it.

Also, I would probably rework the DCG a little bit to make it a little more general and simpler:

article --> [a].
article --> [the].
article --> [].

noun(Noun) --> article, [Noun].

statement(Rule) --> noun(Noun), [is], noun(Object), { Rule =.. [Object, Noun] }.
query(Fact) --> ['Is'], noun(Noun), noun(Object), { Fact =.. [Object, Noun]}.

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

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

Also, there's no real need to make statement1. You can have a DCG rule with more than one body; even if you did need two bodies, you could have them both generate statement/1 structures to match in action/1; you certainly don't need to propagate statement1/1 down that far into the rest of your code.

Last remark, you don't need to quote lowercase atoms. :)

Overall I think you're doing a pretty good job here! This is hard stuff to learn, and the material online is pretty sparse. I hope you keep at it, you're probably starting to see the kinds of cool things you can do with Prolog and DCGs!

Edit: You can catch the error and handle it properly by replacing your last action/1 clause with this:

action(query(Q)) :- 
    catch((Q -> write(yes) ; write(unknown)), 
          error(existence_error(procedure, _), _), 
          write(unknown)), 
    nl.
Daniel Lyons
  • 22,421
  • 2
  • 50
  • 77
  • Thanks! Yes, this has been a challenging assignment. Our text book doesn't cover prolog so that makes it even more fun! I will have to do the catch as I have no way to predict what the TA will input, but I don't understand it. – user2312013 Apr 23 '13 at 17:12
  • Think of it like a database. It's the difference between an empty table and a table that doesn't exist. Not finding something in a place that exists is just life. Not finding the place you want to look for something in is an error. – Daniel Lyons Apr 23 '13 at 17:16
  • So should it be something like this... catch(:query(Q), +Catcher, :write(unknown)) ? What is this "+Catcher"? And is there a way to turn off the auto copy on highlighted text in the SWI IDE? That is extremely annoying. – user2312013 Apr 23 '13 at 17:30
  • I have added some code to the answer to show how to use catch. I don't use the SWI IDE so I can't help you with that. Prolog is pretty simple syntax-wise; I usually edit the code in one window with Emacs or Textadept or Textmate or whatever and then use `make.` to reload it in SWI after meaningful edits. – Daniel Lyons Apr 23 '13 at 17:55
  • Dang, I was close "action(query(Q)) :-catch(( Q -> write(yes)), Q, write(unknown))." Just didn't know the 2nd clause. Thanks mate! I really appreciate the help. Now on to the really hard part of the assignment :( – user2312013 Apr 23 '13 at 18:01
  • Is there anything I need to do to close this post or mark it solved? – user2312013 Apr 23 '13 at 18:07
  • No problem. :) Accepting the answer is sufficient; there's nothing else you have to do. (You could upvote too, if you were so inclined). – Daniel Lyons Apr 23 '13 at 18:09