2015-12-14 7 views
3

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

Пример:

person(sam). 
person(tom). 
person(holly). 

Я хочу вернуть имена тех, кто объявил лично. Я попытался сделать это:

people([]). 
people([X | XS]) :- 
    person(X), 
    people(XS). 

Он работает, вроде, он добавляет sam в список, а затем добавляет sam бесконечно, а не переход на tom, затем holly и затем заканчивается. Может ли кто-нибудь указать мне в правильном направлении, пожалуйста?

+2

@CommuSoft показывает вам, как это сделать. Причина, почему то, что у вас есть, не работает, потому что Prolog начинается с начала фактов, когда вводится новый запрос предложения предиката. Таким образом, с каждым рекурсивным призывом к «людям», это снова начинается с начала фактов. Вот почему 'findall/3' существует. :) – lurker

ответ

5

заказ реализация

Вы можете решить эту проблему, например, с помощью member/2 и аккумулятор:

people(L) :- 
    people([],L). 
people(L,[X|R]) :- 
    person(X), 
    \+member(X,L), 
    people([X|L],R). 
people(L,[]) :- 
    \+ (person(X),\+ member(X,L)). 

Или, если вы знаете, как работать с сократить (!), вы можете использовать @CapelliC's version :

people(L) :- 
    people([],L). 
people(L,[X|R]) :- 
    person(X), 
    \+member(X,L), 
    !, 
    people([X|L],R). 
people(L,L). 

Поэтому каждый раз, когда вы ищете person/1X, так что он не является членом L. Если вы больше не можете найти такого человека, выбирается последнее предложение. В этом случае пустой список [] распространяется в обратном направлении, а для каждого элемента в стеке вызовов добавляется конкретный X.

Использование findall/3 предопределённые

Пролога варианты, которые следуют стандартам ISO, однако, имеют в встроено findall/3:

findall(+Template, :Goal, -Bag) 

Вы можете использовать его следующим образом:

  • Template функтор (это может быть переменная) данных, которые вы хотите получить, здесь X;
  • Goal - предикат (или список предикатов и т. Д.), Которые должны быть выполнены. Пролог, внутренне, вызовет Goal; и
  • Bag - выход: список результатов.

Если вы используете это как:

people(L) :- 
    findall(X,person(X),L). 

он будет генерировать список всех person/1 с:

?- findall(X,person(X),L). 
L = [sam, tom, holly]. 

Есть другие высшие предикаты порядка, которые гарантируют уникальность и т.д.

Семантические различия

Обратите внимание, что findall/3 и наш собственный подход people/1 не являются семантически эквивалентными.Действительно, если ваша база данных содержит человека дважды, он будет дважды в сумке findall/3. Кроме того, наш собственный people/1 будет перечислять списки в любом возможном порядке.

+0

Последняя статья людей/2 действительно неясна ... вы могли бы сделать проще ... – CapelliC

+0

@CapelliC: используя cut '!' В предыдущем пункте? –

+0

Действительно помог мне разобраться с объяснениями, спасибо большое! – Yopper

Смежные вопросы