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

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

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

Директива - это инструкция для компилятора. Директивы используются для установки (предиката) свойств (см. Раздел 4.15), установки флагов (см. Set_prolog_flag/2) и загрузки файлов (этот раздел). Директивы являются условиями формы: - <термин>.

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

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

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

По умолчанию

При использовании грамматик определительных выражений (DCG) в Prolog известно, что 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 Директива Пролога

:- 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 = [].

против

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

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

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

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

?- 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'].

Первопричина

Итак, используя листинг / 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 значение является предпочтительным, поскольку оно облегчает чтение значений при отладке и т. д.

2 ответа

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

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

Я могу сказать, что вы можете быть уверены, что 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".

Директива инициализации SWI-Пролог / 2

Директива SWI-Пролог / 1 директива

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

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

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

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

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

Другие вопросы по тегам