Я на собственном горьком опыте убедился, что в 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
предпочтительнее, потому что это упрощает чтение значений при отладке и т. д.
letter(a)
вместоletter('a')
. Здесь не нужно цитировать, даже в SWI. - person false   schedule 01.08.2017