2016-12-19 21 views
0

Давайте предположим, что у меня есть что-то вроде:Prolog: как написать помощника, который преобразует результат в список?

% person(ID, Name, Age) 
person(_, paul, Age). 
person(_, Name, 20). 
... 

... и вместо типичного связыванию я хотел бы иметь вспомогательную функцию, которая вызывает get_person_list(ID, Name, Age)person но возвращает мне список:

?- get_person_list(_, Name, 20). 
[frank, jack, jane]. 

... для получения списка, например всех лиц в возрасте 20 лет. Как я могу это достичь?

+1

Существует проблема с тем, как вы решили организовать свои данные. У вас есть аргумент для ID, но в вашем примере вы оставляете эти «анонимные». Вместо этого вы можете нормализовать свою базу данных и просто иметь «id_name/2» и «id_age/2», например (я не знаю, что вы пытаетесь моделировать, хотя ... может ли человек иметь имя и возраст, но нет ID? Или имя или возраст неизвестны? В любом случае, нормализуя базу данных и просто оставляя строки для деталей, которые вы не знаете, намного чище, что оставляет «дыры» в таблице.) –

+0

PS: и, конечно, вам нужен «первичный ключ», и обычно идентификатор играет роль первичного ключа. Но поскольку вы оставили код в двух строках, которые у вас есть в вашем примере, я немного смущен. Конечно, это очень плохой первичный ключ. –

ответ

1

В вашем коде вы не указываете параметр для результирующего списка.

Просто позвоните:

findall(Id, person(Id, _, 20), L). 

Вы можете сделать отдельный предикат для этого запроса, если вам действительно нужно это часто, конечно.

get_person_list(Id, List) :- 
    findall(Id, person(Id, _, 20), List). 

Смотрите также bagof/3, как объяснено в ответ Бориса.

+0

... но с этим я буду только в состоянии найти идентификатор, не так ли? Я хотел бы иметь вспомогательную функцию, которая использует '(ID, Name, Age)', так что я могу искать 'ID' или' Name' или 'Age'. Как '(_, Name, 20)' для каждого имени без 'ID' в возрасте 20. Или' (ID, paul, _) 'для всех' paul', независимо от возраста, вместе с идентификатором. – daniel451

+0

@ascenator Да, но это та часть, в которой вы * работаете. У вас есть пример «findall» и один возможный вспомогательный предикат. Посмотрите, как добавить параметры в 'get_person_list' и использовать их в запросе. – coredump

+0

Как работает 'findall (Id, _, 20, L) .'? Вы не указали список 'person', на котором' findall' должен работать ?! – daniel451

1

Вы могли бы просто написать: findall(X,person(_,X,20),L). Это вернет вам список L, который является список вы спросили ...

Пример:

person(_, name1, 20). 
person(_, name2, 20). 
person(_, name3, 20). 
person(_, name4, 20). 
person(_, name5, 20). 

?- findall(X,person(_,X,20),L). 
L = [name1, name2, name3, name4, name5]. 
+0

Если я действительно 'findall (X, person (_, X, 20), L).' Я получаю 'L = [_G6034, _G6031, _G6028, _G6025, _G6022, _G6019, _G6016, _G6013, _G6010 | ...] .' вместо имен в возрасте 20. Что там не так? – daniel451

+0

Возможно, у вас есть имена, начинающиеся с столиц. В записях Prolog используются переменные. В вашем примере он возвращает список с переменными ... В приведенном примере он отлично работает ... – coder

4

Не используйте findall/3 для этого. Это прекрасный пример того, как bagof/3 и setof/3 отличаются от findall/3.

Ваш пример немного странный, так что вот еще одна база данных. Я удалил первый аргумент, потому что вы, кажется, его не используете, и добавил больше строк, чтобы их можно было различать по возрасту. Обратите внимание, что нет смысла иметь свободные переменные в таблице фактов, например person, поэтому все строки имеют значения в обеих позициях.

person(abel, 20). 
person(bill, 30). 
person(clive, 20). 
person(diana, 10). 
person(evan, 200). 
person(fia, 20). 

people_age(Age, Ps) :- 
     bagof(P, person(P, Age), Ps). 

С этим определением people_age/2, вы можете запросить, например:

Кто люди в возрасте от 20?

?- people_age(20, Ps). 
Ps = [abel, clive, fia]. 

Группа людей по их возрасту.

?- people_age(Age, Ps). 
Age = 10, 
Ps = [diana] ; 
Age = 20, 
Ps = [abel, clive, fia] ; 
Age = 30, 
Ps = [bill] ; 
Age = 200, 
Ps = [evan]. 

Кто, по крайней мере 30 лет?

?- people_age(Age, Ps), Age >= 30. 
Age = 30, 
Ps = [bill] ; 
Age = 200, 
Ps = [evan]. 

Последняя можно было бы сделать по-другому, если вы не хотите, чтобы группы по возрасту.Вот как:

?- bagof(P, Age^(person(P, Age), Age >= 30), Ps). 
Ps = [bill, evan]. 

или, может быть,

?- bagof(Age-P, Age^(person(P, Age), Age >= 30), Ps). 
Ps = [30-bill, 200-evan]. 

... если вы не хотите, чтобы выбросить возраст полностью.

Но вы должны просто прочитать «сбор всех решений в Прологе» и предполагаемое использование всех трех: findall/3, bagof/3, setof/3.