5
votes

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?

3

3 Answers

6
votes

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

With the of 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.
5
votes

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))
2
votes

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).