【问题标题】:Applying semicontext for passing additional arguments应用半上下文传递附加参数
【发布时间】:2020-02-26 00:28:25
【问题描述】:

这是来自 Mat 的 answerquestion 的后续问题

从这里开始

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 后的终端序列。

【问题讨论】:

  • 觉得标题不太适合这个问题,所以如果您知道更好的标题,请更改它。
  • 我不确定我是否理解这个问题。你的意思是写“canonical”而不是“conical”吗?
  • @AndersonGreen 就像我在评论中指出的那样,这是一个糟糕的标题。您确实必须阅读 mat 对链接的上一个问题的回答,然后阅读此处的引用以完全理解这个问题。这更像是一个借口,因此 mat 可以扩展上一个问题,因为上一个问题变得越来越大。
  • @false 我不知道 semicontext notation 有一个名字,直到我读了 mat 的答案。然后我在 Markus Triska 的 DCG 文档中找到了它的解释。因为两者都一起使用了Semicontext notation,并强调这是我使用的。我们总是可以创建一个tag synonym。我试图制作一些标签同义词,但似乎需要一些条件才能制作同义词,我相信标签有 5 分,所以我无法制作我想要的。
  • 在人类编程语言中,没有 if 表示法,也没有 while-loop 表示法。这只是一个 if 或 if 语句等

标签: implict-state-passing prolog dcg implicit-state-passing dcg-semicontext


【解决方案1】:

DCG 总是描述了一个列表

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

在上述情况下,似乎您已经使用了 DCG 来描述一个列表,您将其长度用作搜索深度的度量。

这完全没问题,而且非常自然地使用 DCG。

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

有一种直接的方法可以将 DCG 转换为常规的 Prolog 代码 DCG,或者通过常规的 Prolog 解释 DCG 规则。有关详细信息,请参见例如 ISO 草案。

例如,让我们以这个 sn-p 为例:

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,使用终端而不是我们引入的用于描述列表差异的最后两个新参数。

但我们也可以做别的事情

例如,在上面的 sn-p 中,我们注意到 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 参数!它们不再完全出现在这里。只有当我们再次将其扩展回 Prolog 时,它们才会变得可见,或者至少是这样做的一种方法。

但是,还有两个问题:

首先,如果我们真的想要访问这些参数怎么办?当然不是 all 子句只能像这样穿过它们。我们还需要在某处访问它们。其次,还有一个更根本的问题:我们想讨论一个参数,它可以是任何术语,但 DCG 总是描述一个列表

那么,我们如何调和这一切呢?

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

接下来,我们如何在DCG中表达Bc0Bc1之间的关系?为此,我们使用半上下文符号:它让我们谈论以前不在我们描述的列表中的元素。

如 DCG 入门中所述,以下形式的非终结符将很有用:

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

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

因此,如果您想实际访问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) )。

主要优点是:这种表示法让您隐藏附加参数,并且仍然让您可以显式访问它们如果您需要它 ,使用state//2(或直接使用半上下文符号)。

这显然变得越来越有吸引力在你的代码中实际使用的参数越少。如果几乎所有子句都访问参数,那么隐藏它们是没有意义的。但是,您经常会描述贯穿的术语,而您的 DCG 子句中只有极少数实际访问它们。在这种情况下,请考虑使用 DCG 符号来隐式传递它们。

但仍然存在一个问题:如果我们不仅要传递 一个 项,而且要传递两个或更多项,该怎么办?对此有一个非常简单的解决方案:让我们仍然传递一个包含单个元素的列表,但让该元素成为f(Arg1,Arg2,...,Arg_n) 形式的复合词。因此,您对非终端 e//N 的调用可能如下所示:

?- 短语(e(Arg1,Arg2,...,Arg_N), [f(B1,B2,...,B_M)], [Result])。

这里,B1B2 等是您希望隐式传递的参数,以列表的形式,其中包含一个组合所有这些参数的元素。

假设这回答了您的问题,合适的标题可能是:“应用半上下文符号来传递附加参数”。实际问题很清楚,而且我认为这在这种情况下很关键,您希望应用半上下文符号来传递额外的参数即使您已经使用 DCG 符号来描述其他内容。总而言之,一个解决方案是首先释放 DCG 符号,以便您可以使用描述的列表来传递其他参数。

请注意,还有其他解决方案:例如,您可以设计自己的 自定义表示法,与 DCG 表示法完全类似,但扩展为允许您描述 两个独立列表。我把它留作练习。

【讨论】:

  • 谢谢。我会修改这个。
  • 我觉得给它贴个标签绝对不错!我可以想象semicontext 可以被更广泛地解释,因此在比“仅”semicontext-notation 更多的情况下有用。
猜你喜欢
  • 2016-06-21
  • 2014-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-21
  • 2013-01-09
  • 1970-01-01
  • 2017-12-08
相关资源
最近更新 更多