5

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?

repeat
  • 18,496
  • 4
  • 54
  • 166
Mathieu Vidal
  • 53
  • 1
  • 5

3 Answers3

6

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.
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
  • @MathieuVidal. The Prolog toplevel (REPL) **is** quite versatile; it helps me do a lot of I/O implicitly—simply by writing queries and reading answers—as opposed to using the corresponding read_term / write_term API. – repeat Jan 22 '16 at 06:46
  • @MathieuVidal. Want info on how other Prolog processors (not SWI or SICStus) behave in this regard? – repeat Jan 22 '16 at 17:44
5

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))
CAFEBABE
  • 3,983
  • 1
  • 19
  • 38
  • Thanks for these 2 solutions, The first one has the drawback that I must modify my knowlege base. The second one is really the answer I was searching. – Mathieu Vidal Jan 21 '16 at 04:50
2

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

Community
  • 1
  • 1
danielp
  • 1,179
  • 11
  • 26
  • This solution is perhaps good for some implementations of Prolog but it does not work with SWI-Prolog. There, variables starting with _ are just used to remove a warning given by the compiler and their values appear in the answer. Anyway, your answer could be effective for other implementations of Prolog. – Mathieu Vidal Jan 21 '16 at 04:54
  • 1
    @MathieuVidal: You are right, I'm using SICStus and there it works the way I described. I did not consider that other implementations handle it differently. – danielp Jan 21 '16 at 05:28
  • s(X): also works with SWI, but needs to be explicitly enabled. see my post how it can be done. – repeat Jan 21 '16 at 07:17