Что означает символ "-" в Прологе при работе со списками?
Я читал ответ на этот вопрос,
p(X) :- read(A), q(A,X-[]).
q(end,X-X) :- !.
q(A,[A|X]-Y) :- read(B), q(B,X-Y).
Приведенный выше код использует синтаксис List-List. Я немного понимаю, что происходит, но я хочу знать, что именно здесь делает символ / предикат "-". Кроме того, это специфический SWI?
2 ответа
(-)/2
представлять списки различий - довольно необычное соглашение. В старых книгах другой оператор (\)/2
тоже был использован.
Многие предпочитают использовать два отдельных аргумента вместо этого. Есть несколько преимуществ по сравнению с использованием оператора:
Предикат не может быть случайно использован с неустановленной переменной для аргумента. Думать о звонке
q(A, X)
на местеq(A, X-[])
,Выполнение даже немного более эффективно при использовании двух аргументов. Многие системы, такие как SWI, должны создавать каждую
(-)/2
структура динамически.
Тем не менее, есть и другой способ использования списков различий, который часто менее подвержен ошибкам: для этой цели вы можете использовать dcg.
На самом деле в программе есть две ошибки, одна из которых связана с обработкой списка различий. Другая ошибка заключается в том, что программа не обрабатывает конец файла. Было бы лучше использовать end_of_file
на месте end
, Но это поверхностная вещь, которую вы бы нашли рано или поздно.
Другая, более тонкая ошибка связана с взаимодействием между списками различий и сокращением. Я не большой поклонник сокращений, но давайте посмотрим на это правило. Срез режет после того, как все на его левой стороне было выполнено.
q(end_of_file,X-X) :- !.
Первым аргументом является атом end_of_file
, Так как мы используем q/2
только с результатом read/1
в качестве первого аргумента, это может быть только сравнение. Итак, мы находимся в конце файла (или потока). Затем, однако, есть и другие вещи, которые должны быть выполнены. И только в том случае, если это удастся, будет выполнено сокращение: Второй аргумент должен быть (-)/2
(ок, во всех местах есть минус на своем месте). А потом: два аргумента (-)/2
должны быть одинаковыми (должны объединяться). Зачем? Мы находимся в конце файла, но если эти аргументы не объединяются, будет применено другое правило.
Когда это происходит? Вот такой неприятный случай:
p([X,Y,Z]).
И просто введите одну константу, скажем, my_constant.
и затем нажмите Cntrl-d или Cntrl + z. Что должно p/1
делать в таком случае? В идеале, это может произойти сбой после завершения ввода. Тем не менее, он будет ждать дальнейшего ввода.
Причина в неправильном размещении среза. Мы говорим, что p/1
не стойкий Это распространенная ошибка в программах Prolog. Я могу только рекомендовать сократить использование сокращений и принятие DCG. С DCG этого не может быть:
p2(X) :- read(A), phrase(q2(A),X).
q2(end_of_file) --> !.
q2(A) --> [A], {read(B)}, q2(B).
В DCG срез выполняется независимо от аргумента p/1
,
Я думал, что вы имели в виду:.
Это список различий.