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?
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 .
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.
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 ?-.
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.
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))
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With