2016-07-22 12 views
6

Упражнение 09 на этой странице http://www.ic.unicamp.br/~meidanis/courses/mc336/2009s2/prolog/problemas/ просит создать предикат, который содержит повторяющиеся элементы в подсписках.`var (A)` и порядок выполнения

Простое решения является прямым

pack([], []). 
pack([H|T], [I|U]) :- 
    split(H, T, I, P), 
    pack(P, U). 

где раскол split(Head, Tail, HeadGroup, Rest) определяется как

split(A, [], [A], []). 
split(A, [B|T], [A], [B|T]) :- A \= B. 
split(A, [A|T], [A|U], B) :- split(A, T, U, B). 

, который отлично работает и в значительной степени в соответствии с примерным решением, представленным на указанной выше странице ,

Если это решение не удается, такие запросы, как pack(X, [[a], [b, b]]).. Соответствие между двумя наборами решений является биективным (для каждого A в pack(A, B) существует один и только один B), поэтому должно быть лучшее решение.

Один из способов ее решения, чтобы изменить порядок оценки, помогая пролог выбрать нон бесконечную ветвь в зависимости от типа аргумента, как следующий

pack([], []). 
pack(A, B) :- 
    (var(A) -> 
    A = [H|T], 
    B = [I|U], 
    pack(P, U), 
    split(H, T, I, P) 
    ; A = [H|T],                                                         
    B = [I|U], 
    split(H, T, I, P), 
    pack(P, U) 
). 

Два вопроса в связи с этим.

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

Во-вторых, возможно, гораздо более сложный вопрос, есть ли способ переписать решение без var(A), а если нет, то почему?

ответ

4

С декларативной точки зрения, немонотонные конструкций, как var/1 и   (\=)/2 очень проблематично .

Почему? Проверьте это:

?- var(A), A=a. 
A = a. 

?- A=a, var(A). 
false. 

Таким образом, это ломает коммутативности конъюнкции, которая является одним из основных свойств мы полагаемся, когда на самом деле рассуждения о логических программах.

Как насчет (\=)/2, что вы подумали выразили бы, что два условия разные? Проверьте это:

 
?- X \= Y. 
false. 

Нет двух терминов, которые отличаются существуют, да? Кажется немного странным для меня, мягко говоря, так что предикат действительно означает что-то еще.

К счастью, в вашем случае решение очень легко. Просто используйте чистое ограничение dif/2, чтобы обозначить, что два условия: разные. См. для получения дополнительной информации. Вам нужно изменить только одну строку кода  , чтобы сделать ваше решение гораздо более общим.Вместо того, чтобы:

split(A, [B|T], [A], [B|T]) :- A \= B. 

просто использовать dif/2:

 
split(A, [B|T], [A], [B|T]) :- dif(A, B). 

С этим изменением, ваш пример работает полностью, как и ожидалось:

?- pack(X, [[a], [b, b]]). 
X = [a, b, b] ; 
false. 

Обратите внимание, что существующая Пролог литература путь устаревшее , и большинство таких наборов решений исходят от времени, когда dif/2 даже не был доступен в большинство систем Prolog, конечно, не в свободных.

+4

Чистый гений! С 'dif' он теперь может даже решить сумасшедшие вещи, такие как' pack (A, [X, [b]]). – vasily

+2

Перепробовай все мои предыдущие решения. – vasily

+4

Да, это так. 'dif/2' был доступен даже в самой первой системе Prolog, а затем по большому счету игнорировался разработчиками, и теперь становится все более распространенным в реализации снова. Рассуждение во всех направлениях - это, в конце концов, одна из главных достопримечательностей реляционного программирования, поэтому используйте 'dif/2', чтобы выразить беспорядок по срокам в здравом и общем смысле. – mat