Шаг 47.
Основы логического программирования.
Поиск всех решений для цели сразу

    На этом шаге мы рассмотрим поиск всех решений для цели сразу.

    Преимущество рекурсии состоит в том, что, в отличие oт поиска с возвратом, она передает информацию (через параметры) от одного рекурсивного вызова к следующему. Поэтому рекурсивная процедура может хранить память о промежуточных результатах или счетчиках по мере того, как она выполняется.

    Но есть одна вещь, которую поиск с возвратом может делать, а рекурсия - нет. Это поиск всех альтернативных решений в целевом утверждении. Может оказаться, что вам нужны все решения для целевого утверждении, и они необходимы все сразу, как часть единой сложной составной структуры данных. Встроенный предикат использует целевые утверждения в качестве одного из своих аргументов и собирает все решения для этого целевого утверждения в единый список. У предиката findall три аргумента:

    Следующая программа использует findall для печати среднего возраста группы людей.
   domains
      name,address=string
      age=integer
      list=age*
   predicates
      person(name,address,age)
      sumlist(list,age,integer)
   clauses
      sumlist([],0,0).
      sumlist([H |T],Sum,N):-
         sumlist(T,S1,N1),
         Sum=H+S1,
         N=1+N1.
      person("Sherlock Holmes","22B Baker Street",42).
      person("Pete Spiers","Apt. 22, 21st Street", 36).
      person("Mary Darrow", "Suite 2, Omega Home", 51).
   goal
      findall(Age,person(_, _, Age),L), 
      sumlist (L,Sum,N), 
      Ave=Sum/N,
      write("Average=", Ave),nl.
    Текст этой программы можно взять здесь.

    Результат работы программы можно посмотреть на рис.1


Рис.1. Результат работы программы pro47_1.pro

    Предложение findall в этой программе создает список L, в котором собраны все возвраты, полученные из предиката person. Если бы вы захотели собрать список из всех людей, которым 42 года, то вам следовало бы выполнить следующее подцелевое утверждение:

   findall(Who,person(Who,_,42),List)
    Но эта подцель требует от программы, чтобы та содержала объявление домена для результирующегo списка:

   slist=string*

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




Предыдущий шаг Содержание Следующий шаг