Пролог DCG set_prolog_flag double_quotes расположение директивы исходного кода имеет значение; документация?

Я на собственном горьком опыте убедился, что в SWI-Prolog расположение директивы Prolog set_prolog_flag имеет значение в файле исходного кода.

Единственная ценная документация по загрузке файлов исходного кода с директивами, которую я нашел, была в разделе Загрузка Prolog. исходные файлы

Директива — это инструкция для компилятора. Директивы используются для установки (предикатов) свойств (см. раздел 4.15), установки флагов (см. set_prolog_flag/2) и загрузки файлов (этот раздел). Директивы представляют собой термины вида :- ‹term›.

Существует ли документация для SWI-Prolog, описывающая загрузку исходного кода, в которой указывается, применяется ли директива ко всему файлу или зависит от местоположения в файле исходного кода?

Или все строки, загруженные из файла исходного кода, представляют собой простое воспроизведение операторов на верхнем уровне, и местоположение всегда имеет значение?

Дополнение / TL; DR

Дефолт

Известно, что при использовании грамматики определяющего предложения (DCG) в Прологе DCG требует, чтобы ввод был списком кодов символов, например.

?- string_codes("abc123",Cs).
Cs = [97, 98, 99, 49, 50, 51].

и со следующим правилом DCG в файле исходного кода и загруженном в верхний уровень

digit(0) --> "0".

DCG можно использовать с

?- string_codes("0",Cs),phrase(digit(D),Cs,R).
Cs = [48],
D = 0,
R = []

set_prolog_flag

Теперь, чтобы упростить использование DCG вместо использования string_codes директивы Prolog

:- set_prolog_flag(double_quotes, chars).

может использоваться в файле исходного кода и со следующим правилом DCG в файле исходного кода и загружаться в верхний уровень

digit(0) --> "0".

DCG можно использовать с

?- phrase(digit(D),"0",R).
D = 0,
R = [].

Это упустило что-то важное

Оказывается, если set_prolog_flag появляется перед правилом DCG, то пропуск string_codes работает, но если set_prolog_flag появляется после правила DCG, то пропуск string_codes невозможен.

:- set_prolog_flag(double_quotes, chars).
digit(0) --> "0".

?- phrase(digit(D),"0",R).
D = 0,
R = [].

vs

digit(0) --> "0".
:- set_prolog_flag(double_quotes, chars).

?- phrase(digit(D),"0",R).
false.

Рассуждение, которое привело меня к фолу

Хотя я знаю, что большую часть программирования на Прологе можно выполнить только на верхнем уровне, я склонен полагаться на файлы исходного кода и consult/1.
При написании большого количества кода я начал использовать модули. С модулями я обнаружил, что флаги Пролога независимы для каждого модуля.

?- current_prolog_flag(double_quotes,V).
V = string.

?- current_prolog_flag(symbolic:double_quotes,V).
V = string.

?- set_prolog_flag(symbolic:double_quotes,chars).
true.

?- current_prolog_flag(double_quotes,V).
V = string.

?- current_prolog_flag(symbolic:double_quotes,V).
V = chars.

и что модуль верхнего уровня по умолчанию user

?- current_prolog_flag(double_quotes,V).
V = string.

?- current_prolog_flag(user:double_quotes,V).
V = string.

?- set_prolog_flag(double_quotes,chars).
true.

?- current_prolog_flag(double_quotes,V).
V = chars.

?- current_prolog_flag(user:double_quotes,V).
V = chars.

?- set_prolog_flag(user:double_quotes,codes).
true.

?- current_prolog_flag(double_quotes,V).
V = codes.

?- current_prolog_flag(user:double_quotes,V).
V = codes.

что убаюкало меня ложным убеждением, что директива Пролога set_prlog_flag применяется ко всему модулю, независимо от того, где она была написана.

Что сломало форму

При написании большого количества кода примеров было проще хранить все маленькие примеры в одном файле, и с каждым маленьким примером было связано set_prolog_flag. Для примера идентификатора потребовалось два небольших правила DCG, одно для цифр и одно для букв. Правила для цифр были выше правил для букв и работали, но правила для букв имели директиву set_prolog_flag, потому что я работал над ними в то время. Помните, я думаю, что на данный момент директива применяется ко всему файлу. Затем при тестировании ident правила DCG для букв работали, но правила DCG для цифр не срабатывали.

digit(0) --> "0", !.
digit(1) --> "1", !.
digit(2) --> "2", !.

:- set_prolog_flag(double_quotes, chars).

ident(Id) --> letter(C), identr(Cs), { name(Id, [C|Cs]) }.

identr([C|Cs]) --> letter(C), !, identr(Cs).
identr([C|Cs]) --> digit(C), !, identr(Cs).
identr([])     --> [].

letter(a) --> "a", !.
letter(b) --> "b", !.
letter(c) --> "c", !.

?- phrase(ident(Id),"ab12",R).
Id = ab,
R = ['1', '2'].

Основная причина

Таким образом, используя listing/1

?- listing(digit).
digit(0, [48|B], A) :- !,
        A=B.
digit(1, [49|B], A) :- !,
        A=B.
digit(2, [50|B], A) :- !,
        A=B.


?- listing(ident).
ident(C, A, F) :-
        letter(D, A, B),
        identr(E, B, G),
        name(C, [D|E]),
        F=G.

?- listing(identr).
identr([A|D], B, F) :-
        letter(A, B, C), !,
        E=C,
        identr(D, E, F).
identr([A|D], B, F) :-
        digit(A, B, C), !,
        E=C,
        identr(D, E, F).
identr([], A, A).

?- listing(letter).
letter(a, [a|B], A) :- !,
        A=B.
letter(b, [b|B], A) :- !,
        A=B.
letter(c, [c|B], A) :- !,
        A=B.

проблема была очевидна

digit(0, [48|B], A) :- !,
    A=B.

letter(a, [a|B], A) :- !,
        A=B.

эта цифра была преобразована для использования кодов символов 48, а буква была преобразована для использования символов a. Именно тогда я спросил себя, имеет ли значение расположение set_prolog_flag в исходном коде.

Подтверждение основной причины

Чтобы проверить это, я создал небольшой файл с исходным кодом.

digit_before(0) --> "0".

:- set_prolog_flag(double_quotes, chars).

digit_after(0) --> "0".

и на высшем уровне

?- current_prolog_flag(double_quotes,V).
V = string.

?- current_prolog_flag(symbolic:double_quotes,V).
V = string.

?- consult("C:/Users/Eric/Documents/Projects/Calculus Project/test.pl").
true.

?- current_prolog_flag(double_quotes,V).
V = chars.

?- current_prolog_flag(symbolic:double_quotes,V).
V = string.

?- listing(digit_before).
digit_before(0, [48|A], A).

true.

?- listing(digit_after).
digit_after(0, ['0'|A], A).

true

что подтвердило, что директива Пролога set_prolog_flag не применяется ко всему файлу. Обратите внимание, что digit_before преобразуется в 48, а digit_after преобразуется в '0'.

Примечания

Примечание. Директива set_prolog_flag(F,V) также может использоваться на верхнем уровне и не требует предшествующей директивы :-.

Примечание. В примере используется :- set_prolog_flag(double_quotes, chars)., но :- set_prolog_flag(double_quotes, codes). также работает. Использование значения chars предпочтительнее, потому что это упрощает чтение значений при отладке и т. д.


person Guy Coder    schedule 29.07.2017    source источник
comment
Интересно: параметр командной строки -- традиционный - двойные кавычки текст представлен списком кодов символов.   -  person Guy Coder    schedule 01.08.2017
comment
Вы всегда можете написать letter(a) вместо letter('a'). Здесь не нужно цитировать, даже в SWI.   -  person false    schedule 01.08.2017
comment
Формат SO очень хорошо подходит для многих вопросов, в частности потому, что на них очень легко ответить. Но на самом деле это требует многого от спрашивающего. Я действительно нашел этот вопрос слишком длинным, вам действительно следует приложить больше усилий, чтобы сделать их более точными.   -  person false    schedule 02.08.2017
comment
@false Вот почему я поместил большую часть этого в раздел дополнений. Я не ожидаю, что люди прочитают этот раздел, если они не найдут вопрос интересным. Раньше я использовал TL;DR вместо добавки, но это не всегда было уместно.   -  person Guy Coder    schedule 02.08.2017
comment
Для протокола: здесь вы также выявили слабость стандарта. Спасибо! И, пожалуйста, будьте терпеливы, пока это не будет исправлено :-).   -  person false    schedule 02.08.2017
comment
к вашему сведению, я постараюсь связаться с swi-proog людьми, а также с logtalk   -  person Anton Danilov    schedule 03.08.2017
comment
@AntonDanilov Почему комментарий?   -  person Guy Coder    schedule 03.08.2017
comment
@Guy Coder, чтобы сообщить вам, что работа продолжается   -  person Anton Danilov    schedule 03.08.2017
comment
@GuyCoder Я сказал: вот ссылка на т/о обсуждения. если вы хотите что-то сказать по этому поводу, я готов говорить. Хотя речь идет о swi-prolog, тем не менее, это может быть актуально и для logtalk. ... Итак, Пауло, вас интересует проблема, обнаруженная Гаем Кодером в StackOverflow? Пауло Моура: Занят работой. Рассмотрю это позже. Спасибо за ссылку.   -  person Anton Danilov    schedule 09.08.2017


Ответы (2)


В SWI-Prolog директивы и предложения обрабатываются по порядку. Флаги Пролога сложны. Общее правило состоит в том, что они ограничены потоком, где дочерние потоки разделяют флаги от своего создателя, используя семантику копирования при записи, что фактически означает то же самое, что и когда копируются все флаги, за исключением производительности и использования памяти. Но тогда некоторые флаги привязаны к исходному файлу, в котором они появляются. Это означает, что load_files/2 сохраняет состояние флага перед загрузкой и восстанавливает его после. Некоторые другие флаги относятся к модулю, что означает, что API флагов является просто прокси для изменения атрибута модуля. Такие флаги не зависят от потока, поскольку модули являются глобальными. Также обратите внимание, что некоторые флаги влияют на чтение (например, double_quotes), в то время как другие влияют на компилятор (optimise) и большинство из них влияют на поведение во время выполнения.

В идеале документация с current_prolog_flag/2 должна документировать эти аспекты. . Не уверен, что эта документация точна. Для double_quotes указано поддерживается для каждого модуля.

person Jan Wielemaker    schedule 06.08.2017
comment
Спасибо. Я ценю ваш ответ здесь. Поскольку ложно отмечено You have here identified a weakness of the standard, too. Thank you! And please be patient until this is fixed :-)., а Антон Данилов отметил fyi I'll try to contact with swi-prolog people as well as logtalk one's, и поскольку я не знаю всех деталей того, над чем они работают, я подожду, прежде чем принять ответ. - person Guy Coder; 07.08.2017
comment
Для тех, кто не знает, кто такой Ян Вилемейкер, просто загляните в репозиторий SWI-Prolog на GitHub и посмотрите, кто делает большую часть коммиты. - person Guy Coder; 07.08.2017

Я могу сказать, что вы можете убедиться, что директива set_prolog_flag(double_quotes, chars) имеет желаемое поведение (применимость ко всему файлу).

Это можно сделать с помощью директивы initialization/2. с опцией after_load или с помощью initialization/1.

digit_before(0) --> "0".

:- initialization( set_prolog_flag(double_quotes, chars),  after_load ).

digit_after(0) --> "0".

директива инициализации/2 SWI-Prolog

директива инициализации/1 SWI-Prolog

Что касается проблемы, как предложить свои идеи сообществу SWI-Prolog, я надеюсь, что (первоначальное) решение - это наличие второго ответа.

Полезные ссылки:

Исследования Ульриха Ноймеркеля и Фреда Меснарда

Домашняя страница Маркуса Триски

Содержит большое количество разнообразных материалов, посвященных языку программирования Пролог.

person Anton Danilov    schedule 30.07.2017
comment
Я ценю ваш ответ, но он просто указывает мне на те же страницы, на которые я уже ссылался, например. Загрузка исходных файлов Prolog. Я не понимаю, как, если кто-то еще прочитает эти страницы, это удержит их от той же ошибки, что и я. - person Guy Coder; 30.07.2017
comment
@Guy Coder Вы можете предложить свои идеи сообществу swi-prolog. Кроме того, я немного запутался - похоже, вы цените мой ответ, но не согласны. Я думал, что дал возможность не беспокоиться о порядке выполнения директив. довольно нетипично размещать объявления по всему файлу imho - person Anton Danilov; 31.07.2017
comment
Дело не в том, что я согласен или не согласен с вашим ответом, я не понимаю те части, которые ссылаются на initialization. Также я нашел часть With modules I found out that the Prolog flags are independent for each module. странной, поскольку это не был вопрос, а вы ответили на него как на вопрос. - person Guy Coder; 31.07.2017
comment
Вы правы, говоря You may want to suggest your ideas to swi-prolog community. Одной из причин, по которой я задал этот вопрос, было желание посмотреть, было ли это задокументировано где-то, о чем я не знал. Если через несколько недель никто не укажет на какую-либо документацию, я бы предложил ее на сайт SWI-Prolog. - person Guy Coder; 31.07.2017
comment
Если через несколько недель никто не сможет идентифицировать какую-либо опубликованную документацию, объясняющую проблему, с которой я столкнулся, и способы ее избежать, даже для кого-то, кто плохо знаком с Прологом, и если вы добавите к своему ответу, что он не задокументирован нигде, кроме этого вопроса и также добавьте идею вашего предложения You may want to suggest your ideas to swi-prolog community. Я считаю, что это приемлемый ответ. - person Guy Coder; 31.07.2017
comment
Я знаю, что сайт SWI-Prolog является основным местом для документации по SWI-Prolog, но также иногда актуальны вопросы и ответы по SO, и когда я нашел Домашняя страница Маркуса Триски или исследовательские работы Ulrich Neumerkel и Fred Mesnard, например Локализация и объяснение причин незавершающих логических программ с фрагментами отказа Я знаю, что есть еще что-то, но вам нужно искать это или вам указывать на это. - person Guy Coder; 31.07.2017
comment
@GuyCoder Я сказал Пауло Моуре: вот ссылка на s/o обсуждение. если вы хотите что-то сказать по этому поводу, я готов говорить. Хотя речь идет о swi-prolog, тем не менее, это может быть актуально и для logtalk. ... Итак, Пауло, вас интересует проблема, обнаруженная Гаем Кодером в StackOverflow? Пауло Моура: Занят работой. Рассмотрю это позже. Спасибо за ссылку. - person Anton Danilov; 09.08.2017
comment
@GuyCoder Я периодически искал сторонние документы о SWI-Prolog. IIRC, я нашел только документы, связанные с XPCE и другими мелочами. - person Anton Danilov; 22.08.2017
comment
Спасибо за попытку. Нет смысла работать над этим какое-то время. Я подозреваю, что либо Jan, либо false будут иметь что-то, связанное с a weakness of the standard, через несколько месяцев или больше, поэтому, как сказал false, проявите терпение, пока это не будет исправлено. - person Guy Coder; 22.08.2017