我认为这不一定是个好主意。我特别认为这不会比使用 DCG 更容易。您仍然需要编写某种正确的语法,该语法对输入的结构了解更多,而不仅仅是“组合某些单词序列”。也就是说,有一些关于使用 CHR 进行解析的工作,例如参见 CHR Grammars。
您的第一个问题是 CHR 约束是无序的。当您尝试匹配w(L), w(on), w(R) 时,您无法保证L 实际上在输入中R 的左侧。不会为您记录此信息。
所以你能做的就是自己录制。您可以将每个w(X) 替换为w(X, Start, End) 约束,其中Start 和End 是某种输入位置标记。例如,简单地从左到右对标记进行编号:
:- use_module(library(chr)).
:- chr_constraint w/3.
parse(Tokens) :-
parse(Tokens, 0).
parse([], _Position).
parse([Token | Tokens], Position) :-
NextPosition is Position + 1,
w(Token, Position, NextPosition),
parse(Tokens, NextPosition).
您可以按如下方式使用它:
?- parse([the, box, is, on, the, table]).
w(table, 5, 6),
w(the, 4, 5),
w(on, 3, 4),
w(is, 2, 3),
w(box, 1, 2),
w(the, 0, 1).
鉴于这种格式,您可以增强匹配规则以仅组合相邻的输入(其中每个组件的结束标记与“下一个”组件的开始标记相同):
w(the, S, M), w(X, M, E) <=> w([the,X], S, E).
w(L, S, M1), w(on, M1, M2), w(R, M2, E) <=> w(on(L,R), S, E).
w(L, S, M1), w(is, M1, M2), w(R, M2, E) <=> w(is_(L,R), S, E).
(我使用is_ 而不是is,因为is 是一个内置运算符,而is(X, Y) 事实将被打印为X is Y,这在接下来的内容中令人困惑。)
这可以让你取得一些进步:
?- parse([the, box, is, on, the, table]).
w([the, table], 4, 6),
w(is_([the, box], on), 0, 4).
我们看到the和table在位置4到5和5到6被合并成一个短语the, table在位置4到6。还有单词the、box、@987654343 @,on,被合并为一个对象,覆盖位置 0 到 4。但这不正确:“盒子打开”不是一个有效的短语。 “is”右边的短语必须是位置或其他情况。您需要有关短语中子短语类型的更多信息。您需要正确的语法信息,即通过定义不同名称的规则在 DCG 中编码的那种信息。
这是一个扩展版本:
:- chr_constraint noun_phrase/3, situation/3, sentence/3.
w(the, S, M), w(X, M, E) <=>
noun_phrase([the,X], S, E).
w(on, S, M), noun_phrase(R, M, E) <=>
situation(on(R), S, E).
noun_phrase(L, S, M1), w(is, M1, M2), situation(R, M2, E) <=>
sentence(is_(L,R), S, E).
这很有效:
?- parse([the, box, is, on, the, table]).
sentence(is_([the, box], on([the, table])), 0, 6).
但此时您正在编写一个语法丑陋的 DCG,并且您必须手动跟踪大量额外信息。为什么不写 DCG 呢?
noun_phrase([the, X]) -->
[the],
[X].
situation(on(Place)) -->
[on],
noun_phrase(Place).
sentence(is_(Thing, Where)) -->
noun_phrase(Thing),
[is],
situation(Where).
这同样有效:
?- phrase(sentence(Sentence), [the, box, is, on, the, table]).
Sentence = is_([the, box], on([the, table])).
如果您想将此信息放入 CHR 约束中,您可以通过调用该约束来实现。例如,上面的 DCG:
:- chr_constraint sentence/1.
parse(Tokens) :-
phrase(sentence(Sentence), Tokens),
sentence(Sentence).
这会得到与上面相同的 CHR 结果,但没有不再需要的位置标记:
?- parse([the, box, is, on, the, table]).
sentence(is_([the, box], on([the, table]))).