应用半上下文传递附加参数
Applying semicontext for passing additional arguments
这是之前 from Mat's
的后续问题
从此开始
e([number(0)] , t1 , Uc0 , Uc0, Bc0 , Bc0) --> [].
e([number(1)] , t2 , Uc0 , Uc0, Bc0 , Bc0) --> [].
e([number(2)] , t3 , Uc0 , Uc0, Bc0 , Bc0) --> [].
e([op(neg),[Arg]] , u1(E) , [_|Uc0], Uc1, Bc0 , Bc1) -->
[_],
e(Arg , E , Uc0, Uc1, Bc0, Bc1).
e([op(ln),[Arg]] , u2(E) , [_|Uc0], Uc1, Bc0 , Bc1) -->
[_],
e(Arg , E , Uc0, Uc1, Bc0, Bc1).
e([op(add),[Left,Right]], b1(E0,E1) , Uc0 , Uc2, [_|Bc0], Bc2) -->
[_,_],
e(Left, E0, Uc0, Uc1, Bc0, Bc1),
e(Right, E1, Uc1, Uc2, Bc1, Bc2).
e([op(sub),[Left,Right]], b2(E0,E1) , Uc0 , Uc2, [_|Bc0], Bc2) -->
[_,_],
e(Left, E0, Uc0, Uc1, Bc0, Bc1),
e(Right, E1, Uc1, Uc2, Bc1, Bc2).
e(U,B,EL,Es) :-
length(UL, U),
length(BL, B),
phrase(e(EL,Es,UL,[],BL,[]), _).
e(N,EL,Es) :-
length([_|Ls], N),
phrase(e(EL,Es,_,[],_,[]),Ls).
e_count(E, Count) :-
length([_|Ls], E),
findall(., phrase(e(_,_,_,[],_,[]), Ls), Sols),
length(Sols, Count).
然后阅读
For one variable, use a list with a single element that contains just
that variable. If you want to pass around more than one variable, use
a list that contains a single term of the form f(...), capturing all
variables you want to pass around. This is also well worth its
own question.
进化成这样
e( f([number(0)], t1, Uc0, Uc0, Bc0, Bc0) ) --> [].
e( f([number(1)], t2, Uc0, Uc0, Bc0, Bc0) ) --> [].
e( f([number(2)], t3, Uc0, Uc0, Bc0, Bc0) ) --> [].
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, Bc0, Bc1) ) -->
[_],
e( f(Arg, E, Uc0, Uc1, Bc0, Bc1) ).
e( f([op(ln) , [Arg]], u2(E), [_|Uc0], Uc1, Bc0, Bc1) ) -->
[_],
e( f(Arg, E, Uc0, Uc1, Bc0, Bc1) ).
e( f([op(add), [Left,Right]], b1(E0,E1) ,Uc0, Uc2, [_|Bc0], Bc2) ) -->
[_,_],
e(f(Left, E0, Uc0, Uc1, Bc0, Bc1) ),
e(f(Right, E1, Uc1, Uc2, Bc1, Bc2) ).
e( f([op(sub), [Left,Right]], b2(E0,E1) ,Uc0, Uc2, [_|Bc0], Bc2) ) -->
[_,_],
e(f(Left, E0, Uc0, Uc1, Bc0, Bc1) ),
e(f(Right, E1, Uc1, Uc2, Bc1, Bc2) ).
e(U,B,EL,Es) :-
length(UL, U),
length(BL, B),
phrase(e(f(EL,Es,UL,[],BL,[])), _).
e_N(N,EL,Es) :-
length([_|Ls], N),
phrase(e(f(EL,Es,_,[],_,[])),Ls).
e_count(E, Count) :-
length([_|Ls], E),
findall(., phrase(e(f(_,_,_,[],_,[])), Ls), Sols),
length(Sols, Count).
有效,但已注明 use a list that contains a single term of the form f(...)
,此处 f(...)
不在列表中。
我是不是哪里出错了?
补充
参考资料
- Thinking in States 马库斯·特里斯卡
- Prolog DCG Primer 马库斯·特里斯卡
- Extra Arguments 立即学习 Prolog!
带有隐式状态传递的变量命名约定
通常在使用 implict-state-passing 时变量被命名为
S0
→ S1
→...→ S
但是对于我的一元-二叉树示例,我将它们命名为
S0
→ S1
→...→ Sn
以 Sn
而不是 S
结尾。
例如
标准
e(S0,S) :-
这里
e(S0,S2) :-
原因是这个例子很少有 属性 每个 DCG 谓词的长度增加,
例如
e([number(0)] , t1 , Uc0 , Uc0, Bc0 , Bc0) -->
e([op(neg),[Arg]] , u1(E) , [_|Uc0], Uc1, Bc0 , Bc1) -->
e([op(add),[Left,Right]], b1(E0,E1) , Uc0 , Uc2, [_|Bc0], Bc2) -->
所以以 xn
结尾让我再检查一次准确性。
参考:ISO/IEC DTR 13211–3:2006 Definite clause grammar rules
6.1.3 Variable names convention for terminal-sequences
This TR uses variables named S0, S1, ..., S to represent the terminal-sequences
used as arguments when processing grammar rules or when expanding
grammar rules into clauses. In this notation, the variables S0, S1,
..., S can be regarded as a sequence of states, with S0 representing
the initial state and the variable S representing the final state.
Thus, if the variable Si represents the terminal-sequence in a given
state, the variable Si+1 will represent the remaining
terminal-sequence after parsing Si with a grammar rule.
DCG 总是描述了一个列表。
但是哪个列表? 您必须决定如何使用该机制!
在上述情况下,似乎您已经使用 DCG 来描述一个列表,您将其长度用作衡量搜索深度。
这完全没问题,而且是对 DCG 的一种非常自然的使用。
但是,你只能描述一个列表,不能同时描述两个,至少不能用"primary"的方式。您当然可以通过 DCG arguments 同时描述任意多个术语。但是,DCG body 仅限于描述 one 列表,通过调用非终结符和使用终结符。
有一种 straight-forward 方法可以将 DCG 转换为常规 Prolog 代码 而无需 DCG,或者通过常规 Prolog 解释 DCG 规则。有关详细信息,请参阅 ISO 草案。
例如,让我们只看这个片段:
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, Bc0, Bc1) ) -->
[_],
e( f(Arg, E, Uc0, Uc1, Bc0, Bc1) ).
e( f([op(ln) , [Arg]], u2(E), [_|Uc0], Uc1, Bc0, Bc1) ) -->
[_],
e( f(Arg, E, Uc0, Uc1, Bc0, Bc1) ).
我们去掉DCG语法,写成例如为:
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, Bc0, Bc1, [_|Rest0], Rest) ) :-
e( f(Arg, E, Uc0, Uc1, Bc0, Bc1, Rest0, Rest) ).
e( f([op(ln) , [Arg]], u2(E), [_|Uc0], Uc1, Bc0, Bc1, [_|Rest0], Rest) ) :-
e( f(Arg, E, Uc0, Uc1, Bc0, Bc1, Rest0, Rest) ).
(当然请注意,您不应该依赖任何特定的扩展方法,而是始终使用phrase/2
接口来调用DCG。不过,以上是一种 方式来执行这样的扩展,获得常规的 Prolog 代码。)
切换参数
假设我们想返回再次使用 DCG 表示法,因为它非常方便。例如,在使用 DCG 表示法时,我们显然需要考虑更少的变量,这本身就是一个巨大的优势。
因此,我们当然可以回到最初的 DCG,使用终端而不是我们引入的最后两个新参数来描述列表差异。
但我们也可以做其他事情!
例如,在上面的代码片段中,我们注意到 Bc0
和 Bc1
是 仅通过 : None 子句真正关心这些争论。因此,假设我们使用 DCG 机制来描述这两个 参数。
例如,这可能如下所示:
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, [_|Rest0], Rest) ) -->
e( f(Arg, E, Uc0, Uc1, Rest0, Rest) ).
e( f([op(ln) , [Arg]], u2(E), [_|Uc0], Uc1, [_|Rest0], Rest) ) -->
e( f(Arg, E, Uc0, Uc1, Rest0, Rest) ).
这里,我从普通的Prolog版本开始,引入DCG符号,简单地将Bc0
和Bc1
变成了隐式参数!它们根本不再出现在这里。只有当我们再次将其扩展回 Prolog 时,它们才会变得可见,或者至少这是一种方法。
但是,还有两个问题:
首先,如果我们实际上想要访问这些参数怎么办?当然不是 all 子句只是像这样把它们串起来。我们还需要在某处访问它们。其次,还有一个更根本的问题:我们想讨论一个参数,它可以是 任何项 ,但 DCG 总是描述一个 list!
那么,我们如何调和这一切?
最重要的是,我们需要讨论列表,所以解决方案很简单:让我们讨论具有单个元素的列表,即列表[Bc0]
和 [Bc1]
。这使得 DCG 符号在这种情况下完全适用。
接下来,我们如何表达DCG中Bc0
和Bc1
之间的关系?为此,我们使用 半上下文表示法:它让我们可以讨论以前不在我们描述的列表中的元素。
如 DCG 入门中所述,以下形式的非终结符将很有用:
state(S0, S), [S] --> [S0].
您可以将非终结符 state(S0, S)
读作:当前状态为 S0
,此后 为 S
。
因此,如果您想要实际访问 Bc0
并将其与您的其中一个子句中的 Bc1
相关联,您可以这样做:
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, [_|Rest0], Rest) ) -->
state(Bc0, Bc1),
... (something involving Bc0 and Bc1) ...
e( f(Arg, E, Uc0, Uc1, Rest0, Rest) ).
主要优点是:此表示法允许您隐藏 附加参数,仍然 允许您显式访问它们如果你需要它,使用state//2
(或直接使用半上下文符号)。
这显然变得越来越有吸引力在您的代码中实际使用的参数越少。如果几乎所有子句都访问参数,则隐藏它们是没有意义的。但是,您经常会描述贯穿其中的术语,而实际上只有极少数 DCG 子句会访问它们。在这种情况下,请考虑使用 DCG 表示法隐式传递它们。
但仍然存在一个问题:如果我们不仅要传递 一个 任期,而且要传递两个或更多任期,该怎么办?对此有一个非常简单的解决方案:让我们仍然传递一个包含单个元素的列表,但是让t 元素只是 形式为 f(Arg1,Arg2,...,Arg_n)
的复合词。因此,您对非终结符 e//N
的调用可能如下所示:
?- phrase(e(Arg1,Arg2,...,Arg_N), [f(B1,B2,...,B_M)], [Result]).
此处,B1
、B2
等是您希望隐式传递的参数,其形式为带有结合所有这些参数的单个元素。
假设这回答了您的问题,合适的标题可以是:"Applying semicontext notation for passing additional arguments"。实际问题很清楚,我认为这在这种情况下很关键,你想应用半上下文符号来传递额外的参数即使你已经专门使用 DCG 符号来描述其他东西 .总而言之,一个解决方案是首先释放 DCG 符号,以便您可以使用描述的列表来传递额外的参数。
请注意,还有其他解决方案:例如,您可以设计自己的 自定义表示法,完全类似于 DCG 表示法,但扩展方式可以让您同时描述两个独立的列表。我把它留作练习。
这是之前
从此开始
e([number(0)] , t1 , Uc0 , Uc0, Bc0 , Bc0) --> [].
e([number(1)] , t2 , Uc0 , Uc0, Bc0 , Bc0) --> [].
e([number(2)] , t3 , Uc0 , Uc0, Bc0 , Bc0) --> [].
e([op(neg),[Arg]] , u1(E) , [_|Uc0], Uc1, Bc0 , Bc1) -->
[_],
e(Arg , E , Uc0, Uc1, Bc0, Bc1).
e([op(ln),[Arg]] , u2(E) , [_|Uc0], Uc1, Bc0 , Bc1) -->
[_],
e(Arg , E , Uc0, Uc1, Bc0, Bc1).
e([op(add),[Left,Right]], b1(E0,E1) , Uc0 , Uc2, [_|Bc0], Bc2) -->
[_,_],
e(Left, E0, Uc0, Uc1, Bc0, Bc1),
e(Right, E1, Uc1, Uc2, Bc1, Bc2).
e([op(sub),[Left,Right]], b2(E0,E1) , Uc0 , Uc2, [_|Bc0], Bc2) -->
[_,_],
e(Left, E0, Uc0, Uc1, Bc0, Bc1),
e(Right, E1, Uc1, Uc2, Bc1, Bc2).
e(U,B,EL,Es) :-
length(UL, U),
length(BL, B),
phrase(e(EL,Es,UL,[],BL,[]), _).
e(N,EL,Es) :-
length([_|Ls], N),
phrase(e(EL,Es,_,[],_,[]),Ls).
e_count(E, Count) :-
length([_|Ls], E),
findall(., phrase(e(_,_,_,[],_,[]), Ls), Sols),
length(Sols, Count).
然后阅读
For one variable, use a list with a single element that contains just that variable. If you want to pass around more than one variable, use a list that contains a single term of the form f(...), capturing all variables you want to pass around. This is also well worth its own question.
进化成这样
e( f([number(0)], t1, Uc0, Uc0, Bc0, Bc0) ) --> [].
e( f([number(1)], t2, Uc0, Uc0, Bc0, Bc0) ) --> [].
e( f([number(2)], t3, Uc0, Uc0, Bc0, Bc0) ) --> [].
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, Bc0, Bc1) ) -->
[_],
e( f(Arg, E, Uc0, Uc1, Bc0, Bc1) ).
e( f([op(ln) , [Arg]], u2(E), [_|Uc0], Uc1, Bc0, Bc1) ) -->
[_],
e( f(Arg, E, Uc0, Uc1, Bc0, Bc1) ).
e( f([op(add), [Left,Right]], b1(E0,E1) ,Uc0, Uc2, [_|Bc0], Bc2) ) -->
[_,_],
e(f(Left, E0, Uc0, Uc1, Bc0, Bc1) ),
e(f(Right, E1, Uc1, Uc2, Bc1, Bc2) ).
e( f([op(sub), [Left,Right]], b2(E0,E1) ,Uc0, Uc2, [_|Bc0], Bc2) ) -->
[_,_],
e(f(Left, E0, Uc0, Uc1, Bc0, Bc1) ),
e(f(Right, E1, Uc1, Uc2, Bc1, Bc2) ).
e(U,B,EL,Es) :-
length(UL, U),
length(BL, B),
phrase(e(f(EL,Es,UL,[],BL,[])), _).
e_N(N,EL,Es) :-
length([_|Ls], N),
phrase(e(f(EL,Es,_,[],_,[])),Ls).
e_count(E, Count) :-
length([_|Ls], E),
findall(., phrase(e(f(_,_,_,[],_,[])), Ls), Sols),
length(Sols, Count).
有效,但已注明 use a list that contains a single term of the form f(...)
,此处 f(...)
不在列表中。
我是不是哪里出错了?
补充
参考资料
- Thinking in States 马库斯·特里斯卡
- Prolog DCG Primer 马库斯·特里斯卡
- Extra Arguments 立即学习 Prolog!
带有隐式状态传递的变量命名约定
通常在使用 implict-state-passing 时变量被命名为
S0
→ S1
→...→ S
但是对于我的一元-二叉树示例,我将它们命名为
S0
→ S1
→...→ Sn
以 Sn
而不是 S
结尾。
例如
标准
e(S0,S) :-
这里
e(S0,S2) :-
原因是这个例子很少有 属性 每个 DCG 谓词的长度增加,
例如
e([number(0)] , t1 , Uc0 , Uc0, Bc0 , Bc0) -->
e([op(neg),[Arg]] , u1(E) , [_|Uc0], Uc1, Bc0 , Bc1) -->
e([op(add),[Left,Right]], b1(E0,E1) , Uc0 , Uc2, [_|Bc0], Bc2) -->
所以以 xn
结尾让我再检查一次准确性。
参考:ISO/IEC DTR 13211–3:2006 Definite clause grammar rules
6.1.3 Variable names convention for terminal-sequences
This TR uses variables named S0, S1, ..., S to represent the terminal-sequences used as arguments when processing grammar rules or when expanding grammar rules into clauses. In this notation, the variables S0, S1, ..., S can be regarded as a sequence of states, with S0 representing the initial state and the variable S representing the final state. Thus, if the variable Si represents the terminal-sequence in a given state, the variable Si+1 will represent the remaining terminal-sequence after parsing Si with a grammar rule.
DCG 总是描述了一个列表。
但是哪个列表? 您必须决定如何使用该机制!
在上述情况下,似乎您已经使用 DCG 来描述一个列表,您将其长度用作衡量搜索深度。
这完全没问题,而且是对 DCG 的一种非常自然的使用。
但是,你只能描述一个列表,不能同时描述两个,至少不能用"primary"的方式。您当然可以通过 DCG arguments 同时描述任意多个术语。但是,DCG body 仅限于描述 one 列表,通过调用非终结符和使用终结符。
有一种 straight-forward 方法可以将 DCG 转换为常规 Prolog 代码 而无需 DCG,或者通过常规 Prolog 解释 DCG 规则。有关详细信息,请参阅 ISO 草案。
例如,让我们只看这个片段:
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, Bc0, Bc1) ) --> [_], e( f(Arg, E, Uc0, Uc1, Bc0, Bc1) ). e( f([op(ln) , [Arg]], u2(E), [_|Uc0], Uc1, Bc0, Bc1) ) --> [_], e( f(Arg, E, Uc0, Uc1, Bc0, Bc1) ).
我们去掉DCG语法,写成例如为:
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, Bc0, Bc1, [_|Rest0], Rest) ) :- e( f(Arg, E, Uc0, Uc1, Bc0, Bc1, Rest0, Rest) ). e( f([op(ln) , [Arg]], u2(E), [_|Uc0], Uc1, Bc0, Bc1, [_|Rest0], Rest) ) :- e( f(Arg, E, Uc0, Uc1, Bc0, Bc1, Rest0, Rest) ).
(当然请注意,您不应该依赖任何特定的扩展方法,而是始终使用phrase/2
接口来调用DCG。不过,以上是一种 方式来执行这样的扩展,获得常规的 Prolog 代码。)
切换参数
假设我们想返回再次使用 DCG 表示法,因为它非常方便。例如,在使用 DCG 表示法时,我们显然需要考虑更少的变量,这本身就是一个巨大的优势。
因此,我们当然可以回到最初的 DCG,使用终端而不是我们引入的最后两个新参数来描述列表差异。
但我们也可以做其他事情!
例如,在上面的代码片段中,我们注意到 Bc0
和 Bc1
是 仅通过 : None 子句真正关心这些争论。因此,假设我们使用 DCG 机制来描述这两个 参数。
例如,这可能如下所示:
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, [_|Rest0], Rest) ) --> e( f(Arg, E, Uc0, Uc1, Rest0, Rest) ). e( f([op(ln) , [Arg]], u2(E), [_|Uc0], Uc1, [_|Rest0], Rest) ) --> e( f(Arg, E, Uc0, Uc1, Rest0, Rest) ).
这里,我从普通的Prolog版本开始,引入DCG符号,简单地将Bc0
和Bc1
变成了隐式参数!它们根本不再出现在这里。只有当我们再次将其扩展回 Prolog 时,它们才会变得可见,或者至少这是一种方法。
但是,还有两个问题:
首先,如果我们实际上想要访问这些参数怎么办?当然不是 all 子句只是像这样把它们串起来。我们还需要在某处访问它们。其次,还有一个更根本的问题:我们想讨论一个参数,它可以是 任何项 ,但 DCG 总是描述一个 list!
那么,我们如何调和这一切?
最重要的是,我们需要讨论列表,所以解决方案很简单:让我们讨论具有单个元素的列表,即列表[Bc0]
和 [Bc1]
。这使得 DCG 符号在这种情况下完全适用。
接下来,我们如何表达DCG中Bc0
和Bc1
之间的关系?为此,我们使用 半上下文表示法:它让我们可以讨论以前不在我们描述的列表中的元素。
如 DCG 入门中所述,以下形式的非终结符将很有用:
state(S0, S), [S] --> [S0].
您可以将非终结符 state(S0, S)
读作:当前状态为 S0
,此后 为 S
。
因此,如果您想要实际访问 Bc0
并将其与您的其中一个子句中的 Bc1
相关联,您可以这样做:
e( f([op(neg), [Arg]], u1(E), [_|Uc0], Uc1, [_|Rest0], Rest) ) --> state(Bc0, Bc1), ... (something involving Bc0 and Bc1) ... e( f(Arg, E, Uc0, Uc1, Rest0, Rest) ).
主要优点是:此表示法允许您隐藏 附加参数,仍然 允许您显式访问它们如果你需要它,使用state//2
(或直接使用半上下文符号)。
这显然变得越来越有吸引力在您的代码中实际使用的参数越少。如果几乎所有子句都访问参数,则隐藏它们是没有意义的。但是,您经常会描述贯穿其中的术语,而实际上只有极少数 DCG 子句会访问它们。在这种情况下,请考虑使用 DCG 表示法隐式传递它们。
但仍然存在一个问题:如果我们不仅要传递 一个 任期,而且要传递两个或更多任期,该怎么办?对此有一个非常简单的解决方案:让我们仍然传递一个包含单个元素的列表,但是让t 元素只是 形式为 f(Arg1,Arg2,...,Arg_n)
的复合词。因此,您对非终结符 e//N
的调用可能如下所示:
?- phrase(e(Arg1,Arg2,...,Arg_N), [f(B1,B2,...,B_M)], [Result]).
此处,B1
、B2
等是您希望隐式传递的参数,其形式为带有结合所有这些参数的单个元素。
假设这回答了您的问题,合适的标题可以是:"Applying semicontext notation for passing additional arguments"。实际问题很清楚,我认为这在这种情况下很关键,你想应用半上下文符号来传递额外的参数即使你已经专门使用 DCG 符号来描述其他东西 .总而言之,一个解决方案是首先释放 DCG 符号,以便您可以使用描述的列表来传递额外的参数。
请注意,还有其他解决方案:例如,您可以设计自己的 自定义表示法,完全类似于 DCG 表示法,但扩展方式可以让您同时描述两个独立的列表。我把它留作练习。