2
votes

I have just started learning Prolog, and I'm wondering about the first question of this exercise.

%% Suppose we are working with the following knowledge base:
wizard(ron).
hasWand(harry).
quidditchPlayer(harry).
wizard(X) :- hasBroom(X), hasWand(X).
hasBroom(X) :- quidditchPlayer(X).

How does Prolog respond to the following queries?

  1. wizard(ron). -> true
  2. witch(ron). -> undefined procedure
  3. wizard(hermione). -> false
  4. witch(hermione). -> undefined procedure
  5. wizard(harry). -> true
  6. wizard(Y). -> Y = ron ; Y = harry.
  7. witch(Y). -> undefined procedure

Using swipl on Ubuntu, importing the knowledge base for this exercise, first of course trying to decipher what Prolog will returns, and finally checking by myself.

Ok pretty boring stuff until now, I have seen a few answer to these exercises over Github (here, here and there), and I don't understand the answer to the first one: %% 1. wizard(ron). -> true.

First of all the interpreter is complaining about the two definition of what is a wizard:

Warning: /tmp/prolog/ex15.pl:4:
    Clauses of wizard/1 are not together in the source-file
      Earlier definition at /tmp/prolog/ex15.pl:1
      Current predicate: quidditchPlayer/1
      Use :- discontiguous wizard/1. to suppress this message

Secondly, when querying I obtain:

?- wizard(ron).
true ;
false.

The way I get it, first Prolog returns the first fact from the knowledge base, then apply the rule head and find out that ron has neither a broom nor a wand.

All this leading to my question: what subtlety have I missed that makes others writing true as an answer to this query?

1
The interpreter does not really complain about the fact that there are two definitions for wizard, it complains that there are not written immediately one after another.Willem Van Onsem
Furthermore something is true given there is at least one path that returns true.Willem Van Onsem
The exercise.pl you point to is poorly structured. It defines wizard(ron)., a couple of other different facts, then wizard(X) :- .... That means the definition of wizard is discontiguous and many Prolog interpreters will ignore wizard(X) at this point. You need to keep all your wizard(_) definitions next to each other.lurker
@asettouf: you should see "or" not as the "natural language" or (like in "do you want tea or coffee?") but as a logical or ("wizard(ron) holds if true or false."); and "wizard(X) holds if X = harry or X = ron".Willem Van Onsem
In addition to the excellent points raised in these comments, I would like to add thatUsingMixedCaps is typically a_lot_less_readable_than using underscores, which are therefore used in idiomatic Prolog code instead!mat

1 Answers

2
votes

what subtlety have I missed that makes others writing true as an answer to this query?

`?- wizard(ron).`
true;
false

You have the clause (fact) wizard(ron). in your KB.

To make the things clearer you can write the fact also as the rule clause:

wizard(ron) :- true.

As you can see this is pretty redundant notation but useful in some cases as the general fact representation.

So your query can be interpreted as follows:

Is there an wizard called ron?

Since you have the fact wizard(ron) :- true.

Prolog will first unify the goal and the head. In your case unify is trivial comparison because no variables are in the goal and the head.

Then Prolog tries to prove body. The body is builtin predicate true, so you quickly get the answer - true.

Then pressing ';' you initiate the search for the alternative solution. Since no (more) solutions exist for the query wizard(ron), Prolog writes false.

The dot operator designates the clause end. So you wrongly typed dots in your examples:

-> operator means if-then-else relation. It can be used within clause body.

For example you can write std_member/2 as if_member/2

std_member(X, [ X | _  ]).
std_member(X, [ _ | Xs ]) :-
    std_member(X, [ _ | Xs).

if_member(X, [ Y | Xs ]) :-
    X = Y ->  true;
       if_member( X, Xs ).