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

问题描述

使用这样的语法:

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

phrase(b(X),[a,a]) phrase(c(X),a]) 工作没问题。两者都返回 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,413) [b(a)]as[] ? creep
   Fail: (5,[]) ? creep
   Fail: (5,[]) ? 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,[]) ? creep
   Call: (14) asif([b(b(a))],[]) ? creep
   Fail: (14) asif([b(b(a))],[]) ? creep