Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prolog. In a query, how to put a condition on a variable that I do not want in the results?

Imagine that I have the following knowledge base which gives for each person his first name and his age.

person(mary, 39).
person(john, 24).
person(sandy, 17).

Now, I want to retrieve all the persons that are older than 20 years. Furthermore, I just want to collect their first names and not their age. Here, I want to retrieve mary and john.

How to do this generally in Prolog and more specifically in SWI-Prolog?

If we use a variable which is not anonymous, like:

?- person(X, Y), Y > 20.

Prolog will give me the values for both X and Y and I do not want Y.

I cannot use the anonymous variable _ because Prolog cannot link its two instantiations. The following gives an error:

?- person(X, _), _ > 20.

So, how to do this?

like image 609
Mathieu Vidal Avatar asked Jan 20 '16 05:01

Mathieu Vidal


People also ask

How do you write a rule in Prolog?

A rule in Prolog is a clause, normally with one or more variables in it. Normally, rules have a head, neck and body, as in: eats(Person, Thing) :- likes(Person, Thing), food(Thing). This says that a Person eats a Thing if the Person likes the Thing , and the Thing is food .

How do you use not in Prolog?

Because of the problems of negation-as-failure, negation in Prolog is represented in modern Prolog interpreters using the symbol \+ , which is supposed to be a mnemonic for not provable with the \ standing for not and the + for provable.

How do you write a query in Prolog?

In making a query you are asking Prolog whether it can prove that your query is true. If so, it answers "yes" and displays any variable bindings that it made in coming up with the answer. If it fails to prove the query true, it answers "No". Whenever you run the Prolog interpreter, it will prompt you with ?-.


3 Answers

This answer directly follows up on this previous answer by @danielp.

With the prolog-toplevel of swi-prolog you can have either one:

  • show answer substitutions of all variables (default)

  • do not show answer substitutions for variables like _A

For detailed information, read the manual of the Prolog processor you are using!

For SWI: Environment Control (Prolog flags). current_prolog_flag/2. set_prolog_flag/2.

stefan@Lenovo ~ $ swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.15)
...

?- current_prolog_flag(toplevel_print_anon, Flag).   % get default
Flag = true.

?- _A = 1.
_A = 1.

?- _A = 1, X = _A.
_A = X, X = 1.

?- set_prolog_flag(toplevel_print_anon, false).      % toggle flag
true.

?- current_prolog_flag(toplevel_print_anon, Flag).
Flag = false.

?- _A = 1.   % watch out!
true.

?- _A = 1, X = _A.
X = 1.

?- set_prolog_flag(toplevel_print_anon, true).       % restore flag
true.

?- current_prolog_flag(toplevel_print_anon, Flag).
Flag = true.

?- _A = 1.
_A = 1.

?- _A = 1, X = _A.
_A = X, X = 1.
like image 83
repeat Avatar answered Oct 21 '22 23:10

repeat


Why don't you define a predicate

ofintrest(X):- person(X,Y),Y>20.

an query

ofintrest(X).

If you don't want to define a predicate you could also use double negation

person(X,_) ,\+(\+ (person(X,Y), Y>20))
like image 45
CAFEBABE Avatar answered Oct 22 '22 00:10

CAFEBABE


You can define a predicate as already posted in CAFEBABE's answer. Alternatively, you can also give a name that starts with _ to variables whose values should not appear in the answer (as you already noted, occurrences of _ are always distinct variables):

person(X,_Age), _Age > 20.

Update: This is specific to the Prolog implementation. It works for SICStus, but not for SWI by default (see repeat's answer).

like image 35
danielp Avatar answered Oct 21 '22 22:10

danielp