In Prolog (SWI), how to build a knowledge base of

2019-08-23 21:26发布

问题:

I am very new to Prolog and trying to learn.

For my program, I would like to have the user provide pairs of strings which are "types of".

For example, user provides at command line the strings "john" and "man". These atoms would be made to be equal, i.e. john(man).

At next prompt, then user provides "man" and "tall", again program asserts these are valid, man(tall).

Then the user could query the program and ask "Is john tall?". Or in Prolog: john(tall) becomes true by transitive property.

I have been able to parse the strings from the user's input and assign them to variables Subject and Object.

I tried a clause (where Subject and Object are different strings):

attribute(Subject, Object) :-
   assert(term_to_atom(_ , Subject),
   term_to_atom(_ , Object)).

I want to assert the facts that Subject and Object are valid pair. If the user asserts it, then they belong to together. How do I force this equality of the pairs?

What's the best way to go about this?

回答1:

Questions of this sort have been asked a lot recently (I guess your professors all share notes or something) so a browse through recent history might have been productive for you. This one comes to mind, for instance.

Your code is pretty wide of the mark. This is what you're trying to do:

attribute(Subject, Object) :-
  Fact =.. [Object, Subject],
  assertz(Fact).

Using it works like this:

?- attribute(man, tall).
true.

?- tall(X).
X = man.

So, here's what you should notice about this code:

  • We're using =../2, the "univ" operator, to build structures from lists. This is the only way to create a fact from some atoms.
  • I've swapped subject and object, because doing it the other way is almost certainly not what you want.
  • The predicate you want is assertz/1 or asserta/1, not assert/2. The a and z on the end just tells Prolog whether you want the fact at the beginning or end of the database.

Based on looking at your code, I think you have a lot of baggage you need to shed to become productive with Prolog.

  1. Prolog predicates do not return values. So assert(term_to_atom(... wasn't even on the right track, because you seemed to think that term_to_atom would "return" a value and it would get substituted into the assert call like in a functional or imperative language. Prolog just plain works completely differently from that.
  2. I'm not sure why you have an empty variable in your term_to_atom predicates. I think you did that to satisfy the predicate's arity, but this predicate is pretty useless unless you have one ground term and one variable.
  3. There is an assert/2, but it doesn't do what you want. It should be clear why assert normally only takes one argument.
  4. Prolog facts should look like property(subject...). It is not easy to construct facts and then query them, which is what you'd have to do using man(tall). What you want to say is that there is a property, being tall, and man satisfies it.

I would strongly recommend you back up and go through some basic Prolog tutorials at this point. If you try to press forward you're only going to get more lost.

Edit: In response to your comment, I'm not sure how general you want to go. In the basic case where you're dealing with a 4-item list with [is,a] in the middle, this is sufficient:

build_fact([Subject,is,a,Object], is_a(Subject, Object)).

If you want to isolate the first and last and create the fact, you have to use univ again:

build_fact([Subject|Rest], Fact) :-
  append(PredicateAtoms, [Object], Rest),
  atomic_list_concat(PredicateAtoms, '_', Predicate),
  Fact =.. [Predicate, Subject, Object].

Not sure if you want to live with the articles ("a", "the") that will wind up on the end though:

?- build_fact([john,could,be,a,man], Fact).
Fact = could_be_a(john, man)


回答2:

Don't do variable fact heads. Prolog works best when the set of term names is fixed. Instead, make a generic place for storing properties using predefined, static term name, e.g.:

is_a(john, man).

property(man, tall).
property(john, thin).

(think SQL tables in a normal form). Then you can use simple assertz/1 to update the database:

add_property(X, Y) :- assertz(property(X, Y)).


标签: prolog