Как сделать DCG Пролога не жадным? - PullRequest
1 голос
/ 13 февраля 2011

Я хочу написать предикат 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 Ответ

1 голос
/ 14 февраля 2011

Проблема в вашем решении состоит в том, что вы передаете анализ раньше времени (используя cut,!). Когда вы анализируете letters_or_spaces, вы действительно не знаете, сколько входных данных обрабатывать, потому что вам нужно анализировать до второго до последнего.label (в пределах пробелов).

Итак, вы должны позволить движку пролога вернуться в этот предикат, чтобы позволить выбрать правильную фразу в 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, а затем отделить последнюю метку от него.

...