Prolog DCG set_prolog_flag double_quotes源代码指令的位置很重要;文档? [英] Prolog DCG set_prolog_flag double_quotes source code directive location matters; documentation?

查看:71
本文介绍了Prolog DCG set_prolog_flag double_quotes源代码指令的位置很重要;文档?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我了解到使用SWI-Prolog的困难方式,即Prolog指令 set_prolog_flag 的位置在源代码文件中很重要。



我发现关于使用指令加载源代码文件的唯一有价值的文档是在加载Prolog源文件


指令是对编译器的指令。伪指令用于
的set(谓词)属性(请参阅第4.15节),设置标志(请参阅
的set_prolog_flag / 2)和加载文件(本节)。指令是形式为:-< term>的术语


是否有SWI-Prolog文档涵盖了加载指出指令适用于整个文件还是取决于源代码文件中的位置的源代码?



还是从源代码文件加载的所有行仅仅是对顶层语句的简单播放,位置总是很重要?



补编/ TL; DR



默认值



使用确定性子句语法时(Prolog)中的(DCG),已知DCG要求输入为字符代码列表,例如

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

,并在源代码文件中使用以下DCG规则并加载到顶层

  digit(0)->  0。 

DCG可以与



<$ p一起使用$ p> ?-string_codes( 0,Cs),短语(digit(D),Cs,R)。
Cs = [48],
D = 0,
R = []



set_prolog_flag



现在可以更轻松地使用DCG,而不必使用Prolog中的 string_codes 指令

 :-set_prolog_flag(双引号,字符)。 

可以在源代码文件中使用,并在源代码文件中使用以下DCG规则并加载

  digit(0)->  0。 

DCG可以用于

 ?-短语(数字(D), 0,R)。 
D = 0,
R = []。



这遗漏了一些重要的东西



事实证明,如果之前出现 DCG规则,然后跳过 set_prolog_flag 可以,但是如果在DCG规则之后之后出现 set_prolog_flag ,则跳过字符串代码失败。

 :-set_prolog_flag(双引号,字符)。 
digit(0)-> 0。

?-短语(数字(D), 0,R)。
D = 0,
R = []。

vs

  digit(0)->  0。 
:-set_prolog_flag(双引号,字符)。

?-短语(数字(D), 0,R)。
错误。



导致我犯规的原因



虽然我知道可以使用Prolog进行很多编程,但仅在顶层可以完成,但我倾向于依赖源代码文件和咨询/ 1

在编写大量代码时,我开始使用模块。对于模块,我发现Prolog标志对于每个模块都是独立的。

 ?-current_prolog_flag(double_quotes,V)。 
V =字符串。

?-current_prolog_flag(符号:double_quotes,V)。
V =字符串。

?-set_prolog_flag(符号:双引号,字符)。
是。

?-current_prolog_flag(double_quotes,V)。
V =字符串。

?-current_prolog_flag(符号:double_quotes,V)。
V =字符。

并且默认的顶级模块是 user

 ?-current_prolog_flag(double_quotes,V)。 
V =字符串。

?-current_prolog_flag(user:double_quotes,V)。
V =字符串。

?-set_prolog_flag(double_quotes,chars)。
是。

?-current_prolog_flag(double_quotes,V)。
V =字符。

?-current_prolog_flag(user:double_quotes,V)。
V =字符。

?-set_prolog_flag(user:double_quotes,codes)。
是。

?-current_prolog_flag(double_quotes,V)。
V =代码。

?-current_prolog_flag(user:double_quotes,V)。
V =代码。

这使我误以为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(双引号,字符)。

ident(Id)->字母(C),标识符(Cs),{名称(Id,[C | Cs])}。

identr([C | Cs])->字母(C),!,标识符(Cs)。
identr([C | Cs])->数字(C),!,标识符(Cs)。
identr([])-> []。

字母(a)-> 一种, !。
字母(b)-> b ,!
字母(c)-> C, !。

?-短语(ident(Id), ab12,R)。
Id = ab,
R = [‘1’,‘2’]。



根本原因



因此使用列表/ 1

 ? -列表(数字)。 
digit(0,[48 | B],A):-!,
A = B。
digit(1,[49 | B],A):-!,
A = B。
digit(2,[50 | B],A):-!,
A = B。


 ?-列表(标识)。 
ident(C,A,F):-
字母(D,A,B),
identr(E,B,G),
名称(C,[D | E]),
F = G。

?-上市(身份)。
identr([A | D],B,F):-
字母(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)。

?-上市(字母)。
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(双引号,字符)。

digit_after(0)-> 0。

并在顶级

 ?-current_prolog_flag(double_quotes,V)。 
V =字符串。

?-current_prolog_flag(符号:double_quotes,V)。
V =字符串。

?-咨询( C:/ Users / Eric / Documents / Projects / Calculus Project / test.pl)。
是。

?-current_prolog_flag(double_quotes,V)。
V =字符。

?-current_prolog_flag(符号:double_quotes,V)。
V =字符串。

?-上市(digit_before)。
digit_before(0,[48 | A],A)。

是。

?-上市(digit_after)。
digit_after(0,[’0’| A],A)。


这证实了Prolog指令 set_prolog_flag 不适用于整个文件。请注意,digit_before转换为 48 ,digit_after转换为'0'



注释



注意:指令 set_prolog_flag(F,V)也可以使用在顶层,不需要前面的:-



注意:该示例使用了:-set_prolog_flag(双引号,字符)。: -set_prolog_flag(双引号,代码)。也可以。首选使用 chars 值,因为它使调试等时更易于读取值。

解决方案

在SWI-Prolog中,指令和子句按顺序处理。序言标志很复杂。总体规则是它们是线程范围的,子线程使用写时复制语义共享其创建者的标志,这实际上意味着与复制所有标志时的性能和内存使用情况相同。但是,然后,某些标志将作用域限定在它们出现的源文件中。这意味着load_files / 2会在加载之前保存标志的状态,然后再保存。其他一些标志是模块作用域的,这意味着标志API仅仅是更改模块属性的代理。这样的标志不是特定于线程的,因为模块是全局的。还要注意,有些标志会影响读取(例如, double_quotes ),而其他标志会影响编译器( optimise ),而大多数影响



理想情况下,带有 current_prolog_flag / 2 应该记录这些方面。不确定此文档是否正确。对于 double_quotes ,它说为每个模块维护


I learned the hard way that with SWI-Prolog the location for the Prolog directive set_prolog_flag matters in a source code file.

The only documentation I found of value about loading source code files with directives was in 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>.

Is there documentation for SWI-Prolog that covers loading of source code that notes if a directive applies to the entire file or depends on the location in the source code file?

Or is it that all lines loaded from a source code file are just a simple playing of statements into the top-level and location always matters?

Supplement / TL;DR

Default

When using Definitive Clause Grammars (DCG) in Prolog it is known that DCG requires the input to be a list of character codes, e.g.

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

and with the following DCG rule in a source code file and loaded into the top-level

digit(0) --> "0".

the DCG can be used with

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

set_prolog_flag

Now to make it easier to use DCG instead of having to use string_codes the Prolog directive

:- set_prolog_flag(double_quotes, chars).

can be used in a source code file and with the following DCG rule in a source code file and loaded into the top-level

digit(0) --> "0".

the DCG can be used with

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

That left out something important

It turns out that the if set_prolog_flag appears before the DCG rule then skipping string_codes works, but if set_prolog_flag appears after the DCG rule then skipping 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.

The reasoning that led me afoul

While I am aware that a lot of programming with Prolog can be done in just the top-level, I tend to rely on source code files and consult/1.
In writing lots of code I started to use modules. With modules I found out that the Prolog flags are independent for each module.

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

and that the default top-level module is 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.

which lulled me into the false belief that the Prolog directive set_prlog_flag applied to the entire module no matter where it was written.

What broke the mold

In writing lots of example code it was easier to keep all of the little examples in one file and associated with each little example was set_prolog_flag. For an identifier example it needed two little example DCG rules, one for digit and one for letters. The digit rules were above the letter rules and working, but the letter rules had the set_prolog_flag directive because I was working on them at the time. Remember I am thinking that the directive applies to the whole file at this point. Then in testing ident the DCG rules for letters were working but the DCG rules for digits were failing.

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

Root cause

So using 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.

the problem was apparent

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

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

that digit was converted to use character codes 48 and letter was converted to use characters a. That's when I asked myself if the location of set_prolog_flag in source mattered.

Confirming root cause

To test this I created a little source code file

digit_before(0) --> "0".

:- set_prolog_flag(double_quotes, chars).

digit_after(0) --> "0".

and in top-level

?- 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

which confirmed that the Prolog directive set_prolog_flag does not apply to an entire file. Notice that digit_before is converted to 48 and digit_after is converted to '0'.

Notes

Note: The directive set_prolog_flag(F,V) can also be used in the top-level and does not require the preceding :- .

Note: The example used :- set_prolog_flag(double_quotes, chars). but :- set_prolog_flag(double_quotes, codes). also works. Using chars value is preferred because it makes the values easier to read when debugging, etc.

解决方案

In SWI-Prolog, directives and clauses are processed in order. Prolog flags are complicated. The overall rule is that they are thread scoped, where child threads share the flags from their creator using copy-on-write semantics, which effectively means the same as when all flags would be copied except for performance and memory usage. But then, some flags are scoped to the source file in which they appear. This means that load_files/2 saves the state of the flag before the load and restores it afterwards. Some other flags are module scoped, which means the flag API is merely a proxy to changing a module attribute. Such flags are not thread-specific because modules are global. Also note that some flags affect reading (e.g., double_quotes), while others affect the compiler (optimise) and most affect runtime behaviour.

Ideally, the documentation with current_prolog_flag/2 should document these aspects. Not sure this documentation is accurate. For double_quotes it says maintained for each module.

这篇关于Prolog DCG set_prolog_flag double_quotes源代码指令的位置很重要;文档?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆