在语法规则列表而不是原子列表上调用 phrase/2

Calling phrase/2 on a list of grammar rules, rather than a list of atoms

使用这样的语法:

as --> [].
as --> [a], as.
b(b(a)) --> as.
c(X) --> b(X).

phrase(b(X), [a, a]) & phrase(c(X), [a, a]) 没问题。 return X = b(a)..

但是有没有可能统一成这样呢?

phrase(c(X), [b(a)]).
OR:
phrase(c(X), [b(b(a))]).

我没有运气,虽然看起来应该是可能的。我认为这意味着我对 DCG 有一些误解。我知道他们通过差异列表工作,并且当他们可以应用一系列规则来使用列表的所有元素时成功。就 phrase/2 而言,原子或令牌有什么特别之处吗?

轨迹如下所示:

[trace] [4]  ?- phrase(c(X), [b(a)]).
   Call: (5,411) c(_57162, [b(a)], []) ? creep
   Call: (5,412) b(_57162, [b(a)], []) ? creep
   Call: (5,413) [b(a)]as[] ? creep
   Fail: (5,413) [b(a)]as[] ? creep
   Fail: (5,412) b(_57162, [b(a)], []) ? creep
   Fail: (5,411) c(_57162, [b(a)], []) ? creep
false.

[b(a)]as[] 的失败对我来说很有趣。那里正在测试什么?还有...该语法是什么意思?

我知道有些人在对我实际想要完成的事情有更多了解时会更容易回答问题,所以:

偶尔在我的应用程序中我想改写不雅的句子。例如,有时我会遇到类似 ["bake", "that" "many", "pie", "plus", "one"] 的内容。我希望 DCG 将其视为遇到了 ["bake", "x", "pie"]。所以我可以使用 phrase(foo(X), ["x", "pie"]),如果成功,那么我可能想将它包装在语法更高层的另一个规则中。 (为什么不直接调用更高级别的规则来启动呢?一些更高级别的规则在我的语法中非常慢,所以我试图通过先测试较低级别的语法规则来“快速失败”。)

提前感谢您的任何建议!

让我们调整语法规则以更好地表达它们的意思。

请注意,他们正在进行列表处理,如果括号内的元素与列表的前缀统一,则它们会消耗这些元素。 (相反,如果您的 运行 DCG“反向”,它们可能 生成 括号内的元素)

as      --> [].           % consumes nothing
as      --> [a], as.      % consumes an atom 'a', then calls rule as//0
b(b(a)) -->      as.      % consumes nothing, then calls rule as//0
c(X)    -->      b(X).    % consumes nothing, then calls rule b//1

括号内的参数是标准的 Prolog 谓词参数。

当你打电话时

phrase(b(X), [a, a])

这是通过可能性树的成功路径:

  • 使用b(X)消耗[a,a]的前缀:
    • Xb(a)统一调用as//0,不消耗任何东西
  • 使用as的第二个子句来消耗[a,a]的前缀:
    • a被消耗,as//0被调用
  • 使用as的第二个子句来消耗[a]的前缀:
    • a被消耗,as//0被调用
  • 使用as的第一个子句来消耗[]的前缀:
    • 无需进一步调用规则即可成功

因此phrase/2调用成功X=b(a),但b(a)与规则的ba无关。

phrase(c(X), [b(a)]).呢?

  • 使用c(X)消耗[b(a)]的前缀:
    • 没有消费,b(X)被调用。
  • 使用b(X)消耗[b(a)]的前缀: -Xb(a) 统一(头部,而不是列表),不消耗任何内容,调用 as
  • 使用as消耗[b(a)]的前缀:
    • 第一个子句适用,因为它不消耗任何东西,但沿着这条路走下去最终会导致失败,因为我们使用 phrase/2,要求列表在成功时为空(而不是 phrase/3,其中我们可以不绑定 Rest 参数。
    • 第二个子句不适用,因为它消耗 a 但列表是 [b(a)]

失败。

同样适用于 phrase(c(X), [b(b(a))]).

跟踪器输出:

Call: (5,413) [b(a)]as[] ? creep
Fail: (5,413) [b(a)]as[] ? creep

似乎表明,通过唯一适用的规则,即第一个:

as      --> [].

实际列表内容 [b(a)] 必须等于 [](因为由于 phrase/2 调用,我们希望有一个空的“休息”)。您可能会看到优化器的效果。

跟踪器的奇怪输出似乎是由于以下事实 - 至少在我的 swipl 中 - as 被声明为中缀运算符:-)

证明:

?- current_op(Prec,Type,as).
Prec = 700,
Type = xfx.

将谓词重命名为其他名称 - 我现在选择 asif - 更改跟踪器的输出:

?- trace, phrase(c(X), [b(b(a))]).
^  Call: (9) phrase(c(_5760), [b(b(a))]) ? creep
   Call: (12) c(_5760, [b(b(a))], []) ? creep
   Call: (13) b(_5760, [b(b(a))], []) ? creep
   Call: (14) asif([b(b(a))], []) ? creep
   Fail: (14) asif([b(b(a))], []) ? creep