DCG:为DCG {}代码中的变量分配余数

时间:2013-09-06 11:56:55

标签: prolog gnu dcg

这个回答:Very basic dcg prolog syntax帮助了我一点点,但[X]只获得了下一个角色,我想要整个辣酱玉米饼馅,请继续阅读!

我正在使用GNU Prolog编写一个命令选项解析器,我被困在DCG点上。我有这个语法规则,例如,查找“foo --as = json”,我只是无法弄清楚如何得到“任何”的结果,代码:

as_opt --> "--as=", anything, { c( as_opt )}, !.
anything --> [], {c(anything_match)}.

gprolog的扩展是:

as_opt([45, 45, 97, 115, 61|A], B) :-
        anything(A, C),
        c(as_opt), !,
        C = B.

anything(A, B) :-
        c(anything_match), !,
        A = B.

“c()”谓词很简单,只是用于跟踪使用format()执行到stdout的规则,这样我就能看到它运行时发生了什么。如果我手工编写代码,我会这样做:

%% for completeness here!
c(Msg) :- format("Processed ~w~n", [Msg]).

as_opt([45, 45, 97, 115, 61|A], B) :-
        anything(A, C),
        c(as_opt), !,
        C = B,
        { g_assign( gvValue, B )}. %% just for example

回到原来的DCG:

as_opt --> "--as=", anything, { c( as_opt ), gassign( gvValue, ??? )}, !.

那么“???”在哪里是。它有可能......一定是。我将重新阅读关于它如何再次扩展DCG规则的gprolog规则,以防我即将(facepalm)自己,但与此同时,任何协助都会受到欢迎。

谢谢, 肖恩。

3 个答案:

答案 0 :(得分:3)

您要求的是最简单的DCG非终端之一,它描述了任何列表:

list --> [].
list --> [_], list.

要实际访问正在描述的列表,请引入一个参数:

list([])    --> [].
list([L|Ls) --> [L], list(Ls)

你可以像这样使用它:

as_opt(Option) --> "--as=", list(Option).

答案 1 :(得分:3)

有一个更好的解决方案,比mat描述的解决方案更快,避免虚假的选择点,但它需要支持call//1内置的非终端,例如在SWI-Prolog,GNU Prolog和其他Prolog编译器。也在Logtalk上。考虑:

as_opt(Option) --> "--as=", list(Option).

list([L|Ls]) --> [L], list(Ls).
list([]) --> [].

as_opt2(Option) --> "--as=", call(rest(Option)).

rest(Rest, Rest, _).

使用SWI-Prolog更好地说明差异:

?- phrase(as_opt(Option), "--as=json").
Option = [106, 115, 111, 110] ;
false.

?- phrase(as_opt2(Option), "--as=json").
Option = [106, 115, 111, 110].

?- time(phrase(as_opt(Option), "--as=json")).
% 9 inferences, 0.000 CPU in 0.000 seconds (57% CPU, 562500 Lips)
Option = [106, 115, 111, 110] ;
% 2 inferences, 0.000 CPU in 0.000 seconds (63% CPU, 133333 Lips)
false.

?- time(phrase(as_opt2(Option), "--as=json")).
% 6 inferences, 0.000 CPU in 0.000 seconds (51% CPU, 285714 Lips)
Option = [106, 115, 111, 110].

虚假选择点来自list//1非终端的定义。性能差异在于,虽然call//1允许我们简单地访问隐式列表参数,但list//1非终端正在按该隐式参数的元素执行列表复制元素。因此,list//1版本性能在--as=前缀后面的字符是线性的,而call//1性能是常量,与前缀后面的字符数无关:

?- time(phrase(as_opt(Option), "--as=jsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjson")).
% 54 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 2700000 Lips)
Option = [106, 115, 111, 110, 106, 115, 111, 110, 106|...] ;
% 4 inferences, 0.000 CPU in 0.000 seconds (69% CPU, 137931 Lips)
false.

?- time(phrase(as_opt2(Option), "--as=jsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjson")).
% 6 inferences, 0.000 CPU in 0.000 seconds (79% CPU, 333333 Lips)
Option = [106, 115, 111, 110, 106, 115, 111, 110, 106|...].

答案 2 :(得分:1)

我认为你不应该使用全局变量。相反,将参数添加到DCG子句,以获取值:

anything([C|Cs]) --> [C], anything(Cs).
anything([]) --> [].

否则,余数可用作短语/ 3的最后一个参数,在规则成功后,“消耗”标题匹配。