Prolog DCG set_prolog_flag double_quotes 源代码指令位置很重要;文档?
Prolog DCG set_prolog_flag double_quotes source code directive location matters; documentation?
我通过 SWI-Prolog 艰难地了解到,Prolog 指令的位置 set_prolog_flag
在源代码文件中很重要。
我发现的关于使用指令加载源代码文件的唯一有价值的文档是 Loading Prolog source files
A directive is an instruction to the compiler. Directives are used to
set (predicate) properties (see section 4.15), set flags (see
set_prolog_flag/2) and load files (this section). Directives are terms
of the form :- <term>.
SWI-Prolog 是否有涵盖源代码加载的文档,说明指令是应用于整个文件还是取决于源代码文件中的位置?
还是说从源代码文件加载的所有行都只是将语句简单地播放到顶层,位置总是很重要?
补充/TL;DR
默认
在 Prolog 中使用限定从句文法 (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 = [].
对
digit(0) --> "0".
:- set_prolog_flag(double_quotes, chars).
?- phrase(digit(D),"0",R).
false.
导致我犯规的原因
虽然我知道很多使用 Prolog 的编程都可以在顶层完成,但我倾向于依赖源代码文件和 consult/1.
在编写大量代码时,我开始使用 modules。对于模块,我发现 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.
这让我误以为 Prolog 指令 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
在 source 中的位置是否重要。
确认根本原因
为了对此进行测试,我创建了一个小源代码文件
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
确认 Prolog 指令 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
值,因为它使值在调试等时更易于阅读。
我可以说您可以确保 set_prolog_flag(double_quotes, chars)
指令具有所需的行为(适用于整个文件)。
这可以通过使用带有选项 after_load
的 initialization/2.
指令或使用 initialization/1.
来完成
digit_before(0) --> "0".
:- initialization( set_prolog_flag(double_quotes, chars), after_load ).
digit_after(0) --> "0".
SWI-Prolog initializаtion/2 directive
SWI-Prolog initializаtion/1 directive
关于如何向 SWI-Prolog 社区提出您的想法的问题,我希望(初始)解决方案是存在第二个答案。
有用的链接:
Research papers by Ulrich Neumerkel and Fred Mesnard
包含大量专用于编程语言 Prolog 的不同资料。
在 SWI-Prolog 中,指令和子句是按顺序处理的。 Prolog 标志很复杂。总体规则是它们是线程范围的,其中子线程使用写时复制语义共享来自其创建者的标志,这实际上意味着除了性能和内存使用之外,所有标志都将被复制。但是,一些标志的范围仅限于它们出现的源文件。这意味着 load_files/2 在加载之前保存标志的状态并在加载之后恢复它。其他一些标志是模块范围的,这意味着标志 API 只是更改模块属性的代理。这样的标志不是特定于线程的,因为模块是全局的。另请注意,一些标志会影响读取(例如,double_quotes
),而其他标志会影响编译器(optimise
)并且最会影响运行时行为。
理想情况下,带有 current_prolog_flag/2 的文档应该记录这些方面。不确定此文档是否准确。对于 double_quotes
,它表示 为每个模块维护 。
我通过 SWI-Prolog 艰难地了解到,Prolog 指令的位置 set_prolog_flag
在源代码文件中很重要。
我发现的关于使用指令加载源代码文件的唯一有价值的文档是 Loading Prolog source files
A directive is an instruction to the compiler. Directives are used to set (predicate) properties (see section 4.15), set flags (see set_prolog_flag/2) and load files (this section). Directives are terms of the form :- <term>.
SWI-Prolog 是否有涵盖源代码加载的文档,说明指令是应用于整个文件还是取决于源代码文件中的位置?
还是说从源代码文件加载的所有行都只是将语句简单地播放到顶层,位置总是很重要?
补充/TL;DR
默认
在 Prolog 中使用限定从句文法 (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 = [].
对
digit(0) --> "0".
:- set_prolog_flag(double_quotes, chars).
?- phrase(digit(D),"0",R).
false.
导致我犯规的原因
虽然我知道很多使用 Prolog 的编程都可以在顶层完成,但我倾向于依赖源代码文件和 consult/1.
在编写大量代码时,我开始使用 modules。对于模块,我发现 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.
这让我误以为 Prolog 指令 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
在 source 中的位置是否重要。
确认根本原因
为了对此进行测试,我创建了一个小源代码文件
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
确认 Prolog 指令 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
值,因为它使值在调试等时更易于阅读。
我可以说您可以确保 set_prolog_flag(double_quotes, chars)
指令具有所需的行为(适用于整个文件)。
这可以通过使用带有选项 after_load
的 initialization/2.
指令或使用 initialization/1.
digit_before(0) --> "0".
:- initialization( set_prolog_flag(double_quotes, chars), after_load ).
digit_after(0) --> "0".
SWI-Prolog initializаtion/2 directive
SWI-Prolog initializаtion/1 directive
关于如何向 SWI-Prolog 社区提出您的想法的问题,我希望(初始)解决方案是存在第二个答案。
有用的链接:
Research papers by Ulrich Neumerkel and Fred Mesnard
包含大量专用于编程语言 Prolog 的不同资料。
在 SWI-Prolog 中,指令和子句是按顺序处理的。 Prolog 标志很复杂。总体规则是它们是线程范围的,其中子线程使用写时复制语义共享来自其创建者的标志,这实际上意味着除了性能和内存使用之外,所有标志都将被复制。但是,一些标志的范围仅限于它们出现的源文件。这意味着 load_files/2 在加载之前保存标志的状态并在加载之后恢复它。其他一些标志是模块范围的,这意味着标志 API 只是更改模块属性的代理。这样的标志不是特定于线程的,因为模块是全局的。另请注意,一些标志会影响读取(例如,double_quotes
),而其他标志会影响编译器(optimise
)并且最会影响运行时行为。
理想情况下,带有 current_prolog_flag/2 的文档应该记录这些方面。不确定此文档是否准确。对于 double_quotes
,它表示 为每个模块维护 。