应用半上下文传递附加参数

问题描述 投票:3回答:1

这是Mat的question中较早的answer的后续问题

从此开始

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

然后阅读

对于一个变量,请使用包含单个元素的列表,该元素仅包含该变量。如果您要传递多个变量,请使用包含形式为f(...)的单个术语的列表,捕获所有您想要传递的变量。这也很值得自己的问题。

演变成这个

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(...)不在列表中。

我在哪里出错了?

补充

参考

带有隐式状态传递的变量名称约定

通常使用时,变量被命名为

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终端序列的变量名约定

此TR使用名为S0,S1,...,S的变量表示末端序列在处理语法规则或扩展时用作参数语法规则分为子句。在此符号中,变量S0,S1,...,S可以视为状态序列,其中S0表示初始状态和代表最终状态的变量S。因此,如果变量Si表示给定条件下的末端序列状态,变量Si + 1将代表剩余的用语法规则解析Si后的末端序列。

prolog dcg implicit-state-passing dcg-semicontext
1个回答
2
投票

DCG 总是描述了列表

但是哪个列表? 您必须决定如何使用专用机制

在上述情况下,似乎您已经专用 DCG来描述list,其长度将用作搜索深度的度量。

完全可以,并且非常自然地使用DCG。

但是,您只能描述一个列表,不能同时描述两个,至少不能以“主要”方式描述。您当然可以通过DCG arguments同时描述任意多个术语。但是,DCG body仅限于通过调用非终端并使用终端来描述one列表。

有一种直接方法将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。不过,以上是one方式来执行此类扩展,获取常规的Prolog代码。)

切换参数

假设我们想再次back使用DCG表示法,因为它很方便。例如,当使用DCG表示法时,我们显然需要考虑较少的变量,它本身可能已经是一个巨大的优势。

因此,我们当然可以使用终端而不是我们为描述列表差异而引入的最后两个新参数,返回到最初的DCG。

但是我们也可以做其他

例如,在上面的代码段中,我们注意到Bc0Bc1仅通过线程:没有一个子句真正关心这些参数。因此,假设我们专门使用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表示法,并简单地将Bc0Bc1转换为implicit参数!它们不再在此处显示atall。仅当我们再次将其扩展回Prolog时,它们才可见,或者至少这是one做到的方式。

但是,仍然存在两个问题:

首先,如果我们实际上想要访问这些参数怎么办?当然不是all子句只能像这样通过它们。我们还需要在某个地方access。其次,还有一个更根本的问题:我们想谈一个单一的论点,它可以是anyterm,但是DCG总是描述一个list

所以,我们如何协调所有这些?

最重要的是,我们需要讨论列表,所以解决方案很简单:让我们讨论具有单个元素的列表,即列表[Bc0][Bc1]。在这种情况下,这使得DCG标记适用atall

接下来,我们如何表达DCG中Bc0Bc1之间的关系?为此,我们使用semicontexttext表示法

:它让我们谈论先前不在列表中的>]我们正在描述的元素。

如DCG入门中所述,以下形式的非末端将是有用的:

状态(S0,S),[S]-> [S0]。

您可以将非终端state(S0, S)读为:当前状态为S0,而此后

S

因此,if您实际上要访问其中的一个子句中的Bc0并将其与Bc1关联,您可以这样操作:

e(f([op(neg),[Arg]],u1(E),[_ | Uc0],Uc1,[_ | Rest0],Rest))->状态(Bc0,Bc1),...(涉及Bc0和Bc1的东西)...e(f(Arg,E,Uc0,Uc1,Rest0,Rest))。

主要优点是:使用这种符号可以隐藏其他参数,使用still

可以使用state//2(或直接使用半上下文符号)显式地访问它们[。 )。这显然变得越来越有吸引力,[[实际使用的参数越少]在您的代码中。如果几乎所有子句都访问参数,则隐藏它们是没有意义的。但是,您经常会描述贯穿其中的术语,而只有很少的DCG子句实际访问它们。在这种情况下,请考虑使用DCG符号隐式传递它们。

但是仍然存在一个问题:如果我们不仅要传递一个术语,还要传递两个或更多个术语,该怎么办?有一个非常简单的解决方案:让我们仍然在列表中传递一个元素,但是让该元素只是f(Arg1,Arg2,...,Arg_n)形式的

compoundterm

。因此,您对非终结符e//N的调用可能如下所示:?-短语(e(Arg1,Arg2,...,Arg_N),[f(B1,B2,...,B_M)],[结果])。这里,B1B2等是您想要传递的参数,[[隐式,以列表的形式,带有将所有这些参数组合在一起的单个元素。
假设这回答了您的问题,合适的标题可能是:“应用半上下文符号来传递附加参数”。实际问题很清楚,在这种情况下,我认为这很关键,您想要应用半上下文符号来传递附加参数

即使您已经使用DCG符号来描述其他内容

。总而言之,一种解决方案是首先释放DCG表示法,以便您可以使用所描述的列表来传递其他参数。请注意,还有其他解决方案:例如,您可以设计

own

定制表示法,它完全类似于DCG表示法,但是扩展方式允许您在以下位置描述两个独立列表同时。我将其保留为练习。
© www.soinside.com 2019 - 2024. All rights reserved.