Как я могу получить факты из моей базы знаний в список?

Скажем, у меня есть эти факты:

person(fred).
person(jim).
person(mary).

is_person(person(_)).

Я хотел бы получить список, например:

[person(fred), person(jim), person(mary)]

но мой запрос с findall/3 не дает ожидаемого результата:

?- findall(Person,is_person(Person),ListOfPeople).
ListOfPeople = [person(_5034)].

Аналогично с bagof/3:

?- bagof(Person,is_person(Person),ListOfPeople).
ListOfPeople = [person(_5940)].

Я не понимаю, почему findall/3 и bagof/3 так себя ведут.


person Nicholas Hubbard    schedule 02.12.2020    source источник
comment
Используйте bagof/3.   -  person Guy Coder    schedule 02.12.2020
comment
Если вы быстры, вы можете ответить на свой вопрос и получить больше очков. :)   -  person Guy Coder    schedule 02.12.2020
comment
bagof/3 дает мне тот же результат.   -  person Nicholas Hubbard    schedule 02.12.2020


Ответы (1)


Правильный способ:

findall(person(Person),person(Person),ListOfPeople).

or

bagof(person(Person),person(Person),ListOfPeople).

Почему ваш подход не работает? Рассмотреть возможность

findall(Person,is_person(Person),ListOfPeople).

Пролог пытается выполнить is_person(Person).

Есть факт is_person(person(_)).

Итак, для Person = person(_) мы хороши! Так что person(_) будет в списке.

И все, других способов вывести is_person(Person) нет.

Чтобы собрать все Person, нам действительно нужно запросить Person, который соответствует person(Person).

Таким образом:

findall(person(Person),person(Person),ListOfPeople).

Пролог найдет три Person, которые выполняют person(Person). Поскольку в результате должен получиться список не из Person, а из person(Person), мы ставим person/1 вокруг Person в 1-м параметре, шаблоне.

В качестве альтернативы (но немного бессмысленно) вы могли бы:

is_person(person(X)) :- person(X).

?- findall(X,is_person(X),ListOfPeople).

Здесь Пролог собирает все X, для которых is_person(person(X)), которые являются всеми X, которые появляются в (факте) person(X). Таким образом, X это, например, fred. Мы шлепаем person/1 вокруг fred по голове is_person/1. Сделанный.

person David Tonhofer    schedule 02.12.2020
comment
У findall/3 есть некоторые тонкие проблемы (их описывает Ричард О'Киф в Craft of Prolog); Я бы предложил bagof/3 или setof/3. Также следите за свободными переменными. Здесь упоминаются некоторые крайние случаи: swi-prolog.discourse.group/t/ - person Peter Ludemann; 02.12.2020
comment
@PeterLudemann Спасибо, Питер. Я написал их здесь: О findall/3. На самом деле я не смотрел книгу О'Киф. Я посмотрю. - person David Tonhofer; 02.12.2020