Пролог. В запросе, как поставить условие на переменную, которую я не хочу видеть в результатах?

Представьте, что у меня есть следующая база знаний, которая дает каждому человеку его имя и возраст.

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

Теперь я хочу получить всех лиц старше 20 лет. Кроме того, я просто хочу собрать их имена, а не их возраст. Здесь я хочу получить mary и john.

Как это сделать вообще на Прологе и конкретно на SWI-Prolog?

Если мы используем переменную, которая не является анонимной, например:

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

Пролог даст мне значения как для X, так и для Y, и я не хочу Y.

Я не могу использовать анонимную переменную _, потому что Пролог не может связать два ее экземпляра. Следующее дает ошибку:

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

Итак, как это сделать?


person Mathieu Vidal    schedule 20.01.2016    source источник


Ответы (3)


Почему бы вам не определить предикат

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

запрос

ofintrest(X).

Если вы не хотите определять предикат, вы также можете использовать двойное отрицание

person(X,_) ,\+(\+ (person(X,Y), Y>20))
person CAFEBABE    schedule 20.01.2016
comment
Спасибо за эти 2 решения. У первого есть недостаток, заключающийся в том, что я должен изменить свою базу знаний. Второй - действительно ответ, который я искал. - person Mathieu Vidal; 21.01.2016

Этот ответ непосредственно следует за предыдущим ответом от @danielp.

С prolog-toplevel из swi-prolog вы можете иметь любой :

  • показать подстановки ответов всех переменных (по умолчанию)

  • не показывать замены ответов для таких переменных, как _A

Для получения подробной информации прочтите руководство по используемому вами процессору Prolog!

Для SWI: Контроль среды (флаги Prolog). 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.
person repeat    schedule 21.01.2016
comment
@Матье Видаль. Верхний уровень Пролога (REPL) является весьма универсальным; это помогает мне выполнять множество операций ввода-вывода неявно — просто путем написания запросов и чтения ответов — в отличие от использования соответствующего API read_term/write_term. - person repeat; 22.01.2016
comment
@Матье Видаль. Хотите узнать, как другие процессоры Prolog (не SWI или SICStus) ведут себя в этом отношении? - person repeat; 22.01.2016

Вы можете определить предикат как уже опубликованный в ответе CAFEBABE. В качестве альтернативы вы также можете дать имя, начинающееся с _, переменным, значения которых не должны появляться в ответе (как вы уже заметили, вхождения _ всегда являются разными переменными):

person(X,_Age), _Age > 20.

Обновление: относится к реализации Prolog. Он работает для SICStus, но не для SWI по умолчанию (см. повторить ответ).

person danielp    schedule 20.01.2016
comment
Это решение, возможно, хорошо для некоторых реализаций Пролога, но оно не работает с SWI-Прологом. Там переменные, начинающиеся с _, просто используются для удаления предупреждения, выданного компилятором, и их значения появляются в ответе. В любом случае, ваш ответ может быть эффективным для других реализаций Пролога. - person Mathieu Vidal; 21.01.2016
comment
@MathieuVidal: Вы правы, я использую SICStus, и он работает так, как я описал. Я не учел, что другие реализации обрабатывают это по-другому. - person danielp; 21.01.2016
comment
s(X): также работает с SWI, но требует явного включения. см. мой пост, как это можно сделать. - person repeat; 21.01.2016