如何让Prolog的DCG不贪心?

时间:2011-02-12 22:42:14

标签: prolog grammar dcg

我想编写一个DCG谓词,它将接受一个字母标签,一个空格,一个可能包含空格或字母的伪束,另一个空格和另一个字母标签,最后是一段句子,如下所示:

label_madness --> label(Table1), " ", label_with_spaces(Rel), " ", label(Table2), ".".

以下是标签代码:

label(A) --> letters(S), {string_to_atom(S, A)}, !.
label_with_spaces(A) --> letters_or_spaces(S), {string_to_atom(S, A)}, !.

letters([C|D]) --> letter(C), letters(D), !.
letters([C]) --> letter(C), !.

letters_or_spaces([C|D]) --> letter(C), letters_or_spaces(D), !.
letters_or_spaces([C|D]) --> spacehyphen(C), letters_or_spaces(D), !.
letters_or_spaces([C]) --> letter(C), !.
letters_or_spaces([C]) --> spacehyphen(C), !.

letter(C) --> [C], {"a"=<C, C=<"z"}, !.
letter(C) --> [C], {"A"=<C, C=<"Z"}, !.
spacehyphen(E) --> " ", {from_list("-", E)}, !. % spaces are replaced with hyphens in the pseudolabel
from_list([E], E).

现在当我向label_madness提供"Alice is responsible for Bob."这样的字符串时,它会失败。出于神秘的原因,trace拒绝使用,但我认为它失败了,因为DCG匹配is responsible for Bob的整个Rel。我试过标签之间的非空格分隔符,它工作正常。我应该如何重写label_with_spaces谓词以仅消耗所需的输入?

1 个答案:

答案 0 :(得分:1)

您的解决方案中的问题是您在时间之前提交解析(使用剪切,!) 当您解析letters_or_spaces时,您实际上不知道要处理多少输入,因为您必须解析直到倒数第二个标签(在空格内)。

所以,你应该让prolog引擎在该谓词中回溯,以允许在letters_or_spaces中选择正确的短语。 类似的东西(只显示代码的更改,即从一些谓词子句中删除):

label(A) --> letters(S), {string_to_atom(S, A)}.
label_with_spaces(A) --> letters_or_spaces(S), {string_to_atom(S, A)}.
letters_or_spaces([C|D]) --> letter(C), letters_or_spaces(D).
letters_or_spaces([C|D]) --> spacehyphen(C), letters_or_spaces(D).
letters_or_spaces([C]) --> letter(C).
letters_or_spaces([C]) --> spacehyphen(C).

您也可以稍微改变您的解析器,而不是使用回溯,只需解析到letters_or_spaces中的句点,然后从中分割出最后一个标签。