我通过 SWI-Prolog 惨痛地了解到 Prolog 指令的位置set_prolog_flag
重要的是源代码文件。
我发现的关于使用指令加载源代码文件的唯一有价值的文档位于加载Prolog源文件 http://www.swi-prolog.org/pldoc/man?section=consulting
指令是给编译器的指令。指令用于
设置(谓词)属性(参见第 4.15 节),设置标志(参见
set_prolog_flag/2)并加载文件(本节)。指令就是条款
形式:- 。
SWI-Prolog 是否有文档涵盖源代码的加载,并注明指令是否适用于整个文件或取决于源代码文件中的位置?
或者从源代码文件加载的所有行都只是将语句简单地播放到顶层并且位置总是很重要?
补充/TL;DR
Default
当在 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 = []
设置序言标志
现在可以更轻松地使用 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
出现before然后跳过 DCG 规则string_codes
有效,但如果set_prolog_flag
出现after然后跳过 DCG 规则string_codes
fails.
:- 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.
导致我发生冲突的推理
虽然我知道很多使用 Prolog 的编程都可以在顶层完成,但我倾向于依赖源代码文件和咨询/1 http://www.swi-prolog.org/pldoc/man?predicate=consult/1.
在编写大量代码时我开始使用modules http://www.swi-prolog.org/pldoc/man?section=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'].
根本原因
所以使用清单/1 http://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
这证实了 Prolog 指令set_prolog_flag
不适用于整个文件。请注意,digit_before 已转换为48
并将 digital_after 转换为'0'
.
Notes
注:指令set_prolog_flag(F,V)
也可以用在顶层,不需要前面的:-
.
注:所使用的示例:- set_prolog_flag(double_quotes, chars).
but :- set_prolog_flag(double_quotes, codes).
也有效。使用chars
value 是首选,因为它使值在调试等时更容易读取。