Структура (списки различий) Пролог
Этот вопрос относится к материалу в главе 3 книги: Программирование на Прологе, Clocksin and Mellish, Ed 5
На странице 72 этой книги отображается программа, использующая список различий:
partsOf(X,P):- partsacc(X,P,Hole) , Hole=[].
partsacc(X,[X|Hole],Hole):-basicpart(X).
partsacc(X,P,Hole):- assembly(X,Subparts), partsacclist(Subparts, P, Hole).
partsacclist([],Hole,Hole).
partsacclist([P|T], Total, Hole):- partsacc(P,Total,Hole1), partsacclist(T,Hole1,Hole).
Во многих онлайн-уроках используется следующий формат использования "-", например:
append([ A , B , C | R1 ] – R1 , [ D , E | R2 ] – R2 , R3)
Мои вопросы:
В чем разница между этими двумя представлениями (использование - и не использование)
В каких ситуациях лучше всего использовать каждый из них?
Спасибо
3 ответа
Во что бы то ни стало: не используйте (-)/2
или же (\)/2
или любой другой оператор для представления "списков различий". Причина в том, что вы часто будете иметь предикат с одним аргументом списка и внутренний предикат, который использует список различий. И то, и другое имеет одинаковую арность и, возможно, одно и то же имя, может привести к путанице. Еще хуже, это могло бы работать для "некоторых случаев". Кроме того, этот оператор будет нести определенные расходы, которых вы можете избежать с помощью двух отдельных аргументов.
Попробуйте придерживаться чистого соглашения об именах. То есть S0
, S1
... S
, Таким образом, аргументы, представляющие список различий, будут легко видны. Чтобы лучше подчеркнуть, что эти аргументы принадлежат друг другу, некоторые люди не используют пробел после разделяющей запятой, тогда как они используют его для других аргументов. Таким образом:
p(L+R, S0,S) :-
p(L, S0,S1),
p(R, S1,S).
Кроме того, (-)/2
имеет другое значение в Прологе. Используется для представления пары Key-Value
, как в keysort/2
,
Любая книга по Прологу, которую я знаю, предлагающая оператора для списков различий, была написана в 1980-х годах.
Мой опыт в Прологе ограничен, но кажется, что старые тексты, как правило, используют либо -
или другой персонаж (например, \
) для обозначения списка и его хвоста. Более новый код Prolog всегда использует два аргумента (как в вашем первом примере). Например, все встроенные и библиотечные предикаты в SWI-Prolog последовательно используют два отдельных аргумента.
Теоретически, нет разницы, какой стиль вы предпочитаете. Я думаю, не повредит быть последовательным в своем коде.
На практике разница в том, что вместо составного термина, содержащего два списка в одном аргументе, у вас есть два аргумента, которые должны быть более эффективным представлением.
РЕДАКТИРОВАТЬ
Не забудьте также прочитать ответ @false.
Я согласен с тем, что сказал Борис (+1) относительно разных представлений. Более того, на мой взгляд, это тот случай, когда вы должны явно использовать DCG вместо различий в списке кодирования. Рассмотрим, например, следующую версию кода:
parts(X) --> { basicpart(X) }, [X].
parts(X) --> { assembly(X, Parts) }, assembly_(Parts).
assembly_([]) --> [].
assembly_([X|Xs]) --> parts(X), assembly_(Xs).
Использование, после определения assembly/2
а также basicpart/1
точно так же, как в вашем примере:
?- phrase(parts(X), Ls).
DCG имеет четкую декларативную и легкую для чтения интерпретацию и требует меньше аргументов.