Предикаты (@<)/2
и (@>=)/2
являются не монотонна, и как таковые не обладают свойствами, которые необходимы, чтобы правильно описать то, что «объединение» означает в целом. Программы, которые используют такие предикаты, могут работать в определенных случаях, но обычно приводят неверные результатов в целом.
Чтобы показать суть проблемы, следующее важное декларативный свойство нарушается этими предикатами:
Добавление цель может максимально уменьшить, никогда не распространяется, множество решений.
Это монотонности сломана этими свойствами, как показано, например, с:
?- Y @< X.
false.
решения не существует, да? В частности, обязательноX=1
, Y=0
is не решение, не так ли? Хорошо посмотрим:
?- X=1, Y=0, Y @< X.
X = 1,
Y = 0.
Whaaat? Нам сказали, что есть нет решения вообще!
Другими словами, мы просто не можем применять даже самые фундаментальные логические рассуждения при работе с этими предикатами. На мой взгляд, поэтому лучше избегать таких предикатов, если вы хотите максимально использовать преимущества логического программирования.
Ограничения обеспечивают выход из этого беспорядка. Ограничения корректно работают во всех шаблонах создания экземпляров и позволяют использовать более общие программы, которые работают во всех направлениях.
Вот программа, которая описывает такое слияние списков целых, используя CLP (FD) ограничения:
merge_([A|T], [], [A|T]).
merge_([], [A|T], [A|T]).
merge_([A|T], [B|U], [A|V]) :- A #< B, merge_(T, [B|U], V).
merge_([A|T], [B|U], [B|V]) :- A #>= B, merge_([A|T], U, V).
Целое число analogon в примере вы процитировать:
?- merge_(A, [1,2,3], [1,2,3,4]).
A = [4].
Итак, это работает точно так, как ожидалось. Единственный недостаток: для этого требуется, чтобы мы определили объекты, которые мы хотим обосновать, до целых чисел. На практике очень много программ в любом случае делают разницу по целым, так что это часто бывает приемлемым.
Аналогичные обобщения возможны и для других доменов. Однако целые числа относятся к числу наиболее часто используемых доменов, поэтому все широко используемые системы Prolog поставляются с ограничениями CLP (FD) , которые я рекомендую в качестве полезной отправной точки или даже решения для таких проблем.
Кстати, другой пример вы цитируете также работает полностью, как ожидается, если вы просто используете CLP (FD) ограничения:
?- merge_(A, B, [1,2,3]).
A = [1, 2, 3],
B = [] ;
A = [],
B = [1, 2, 3] ;
A = [1],
B = [2, 3] ;
A = [1, 2],
B = [3] ;
etc.
Ответ вы приняли требует, чтобы элементы списка быть числовым. Вам нужно, чтобы это работало с общими атомными элементами? – lurker
Я хотел бы использовать общие атомные элементы, но сейчас я очень рад понять, в чем проблема. – vasily