Звучит так, будто вы пытаетесь написать собственную версию findall / 3 , возможно, ограниченную особым случаем основной цели. Выполнение этого вообще (построение списка всех решений для данной цели) в пользовательском предикате Prolog невозможно без обращения к побочным эффектам с assert / retract .
Однако ряд полезных особых случаев может быть реализован без таких «уловок». Поэтому было бы полезно узнать, какой предикат определяет ваши «все возможные элементы». [Также может быть полезно указать, какую реализацию Prolog вы используете, хотя бы для того, чтобы ответы могли содержать ссылки на документацию для этой версии.]
Один важный особый случай - это когда «вселенная» потенциальных кандидатов уже существует в виде списка. В этом случае мы действительно просим найти подсписок «всех возможных элементов», которые удовлетворяют определенной цели.
findSublist([ ],_,[ ]).
findSublist([H|T],Goal,[H|S]) :-
Goal(H),
!,
findSublist(T,Goal,S).
findSublist([_|T],Goal,S) :-
findSublist(T,Goal,S).
Многие прологи позволят вам передавать имя цели предиката как «атом», но если у вас есть конкретная цель, вы можете опустить средний аргумент и просто жестко закодировать ваше конкретное условие в среднее предложение. аналогичной реализации.
Добавлено в ответ на опубликованный код:
Я думаю, у меня есть проблеск того, что вы пытаетесь сделать. Трудно понять, потому что вы не делаете это правильно. Ваш предикат bp / 4 содержит одно рекурсивное предложение, в котором по-разному пытались использовать синтаксис AND или OR, чтобы связать вызов addIn / 4 с вызовом bp / 4 сама.
Очевидно, вы ожидаете, что обтекание bp / 4 вокруг addIn / 4 таким образом каким-то образом заставит addIn / 4 накапливать или перебирать его решения. Не будет Это может помочь вам увидеть это, если мы проанализируем, что происходит с аргументами bp / 4 .
Вы вызываете формальные аргументы bp (NB, C, OL, A) с простыми целыми числами, привязанными к NB и C, со списком целых чисел, привязанными к OL, и с A в качестве несвязанного ответа «output». Обратите внимание, что ничего не делается со значением NB, поскольку оно не передается в addIn / 4 и передается без изменений в рекурсивный вызов bp / 4 .
Основываясь на именах переменных, используемых addIn / 4 и поддерживающем предикате insert / 4 , я предполагаю, что NB должен был означать «количество бинов». Во-первых, вы устанавливаете NB = 3 в своем предложении test / 0 , а позже вы «жестко кодируете» три пустых списка в третьем аргументе при вызове addIn / 4 . Какой бы ответ вы ни получили от bp / 4 , он получен из того, что addIn / 4 может сделать с его первыми двумя передаваемыми аргументами C и OL из bp / 4 . Как мы уже отмечали, C - это целое число, а OL - список целых чисел (по крайней мере, так: test / 0 вызывает bp / 4 ).
Итак, давайте попробуем указать, что addIn / 4 должен делать с этими аргументами. Внешне addIn / 4 кажется разумно структурированным для саморекурсии. Его первое предложение представляет собой простое условие завершения, которое, когда второй аргумент становится пустым списком, объединяет третий и четвертый аргументы, и это дает «ответ» А вызывающей стороне.
Второе предложение для addIn / 4 , похоже, согласуется с этим подходом. Как написано, он удаляет элемент «head» из списка во втором аргументе и пытается найти «bin» в третьем аргументе, в который может быть вставлен элемент, сохраняя сумму этого bin под «cap», заданным C. Если все идет хорошо, в конечном итоге все числа из OL присваиваются ячейке, все ячейки имеют итоговые значения под заглушкой C, и ответ A передается обратно вызывающей стороне. Написанный way addIn / 4 оставляет много возможностей для улучшения только в элементарной ясности, но он может делать то, что вам нужно.
Что возвращает нас к вопросу о том, как вы должны собирать ответы, выданные addIn / 4 . Возможно, вы счастливы распечатать их по одному. Возможно, вы хотели собрать все решения, созданные addIn / 4 , в один список. Чтобы закончить упражнение, мне нужно, чтобы вы уточнить, что вы действительно хотите сделать с ответами из addIn / 4 .
Допустим, вы хотите распечатать их все и затем остановиться, в особом случае - ничего не печатать, если передаваемые аргументы не позволяют решить проблему. Тогда вам наверняка захочется чего-нибудь такого:
newtest :-
addIn(12,[7, 3, 5, 4, 6, 4, 5, 2], Answer),
format("Answer = ~w\n",[Answer]),
fail.
newtest.
Это стандартный способ получения предиката addIn / 4 , чтобы попробовать все возможные решения, а затем остановиться с "провальным" успехом второго предложения newtest / 0 .
(Добавлено) Предложения по кодированию addIn / 4:
- Это сделает код более читабельным и понятным, если имена переменных понятны. Я бы предложил использовать Cap вместо C в качестве первого аргумента для addIn / 4 и BinSum, когда вы берете сумму элементов, назначенных для "bin". Аналогично, Bin будет лучше там, где вы использовали участников. В третьем аргументе addIn / 4 (в главе второго предложения) вам не нужна явная структура списка [F | R], поскольку вы никогда не ссылаетесь ни на часть F, ни на R. Так что я бы использовал бункеры.
- Некоторые из ваших предикатных вызовов не достигают многого, что вы не можете сделать легче. Например, ваш второй вызов sumlist / 2 включает в себя список с одним элементом. Таким образом, сумма точно такая же, как у этого элемента, то есть ElementLength совпадает с Element. Здесь вы можете просто заменить оба вызова на sumlist / 2 одним таким вызовом:
SumList ([Элемент | Bin], BinSum)
а затем проведите тест, сравнивая BinSum с Cap. Точно так же ваш вызов append / 3 просто присоединяет элемент Element к началу списка (я звоню) Bin, так что вы можете просто заменить то, что вы назвали New, на [Element | Bin].
- Вы использовали дополнительную пару скобок вокруг последних четырех подцелей (во втором пункте для addIn / 4 ). Поскольку AND подразумевается для всех подцелей этого пункта, использование дополнительной пары скобок не требуется.
- Код insert / 4 сейчас не отображается, но в особых случаях он может быть источником непреднамеренного «возврата». Лучшим подходом было бы, чтобы первый вызов (в настоящее время member / 2 ) был вашей единственной точкой неопределенности, т.е. когда вы выбираете один из бинов, сделайте это, заменив его свободной переменной, которая получает объединяется с [Элемент | Бин] рядом с последним шагом.