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

3

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?

Scrubland answered 20/1, 2016 at 5:58 Comment(0)
A
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))
Antalya answered 20/1, 2016 at 6:5 Comment(1)
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.Scrubland
B
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.
Boudicca answered 21/1, 2016 at 7:7 Comment(2)
@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.Boudicca
@MathieuVidal. Want info on how other Prolog processors (not SWI or SICStus) behave in this regard?Boudicca
A
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))
Antalya answered 20/1, 2016 at 6:5 Comment(1)
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.Scrubland
C
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).

Chantell answered 20/1, 2016 at 7:0 Comment(3)
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.Scrubland
@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.Chantell
s(X): also works with SWI, but needs to be explicitly enabled. see my post how it can be done.Boudicca

© 2022 - 2024 — McMap. All rights reserved.