Перевод в DCG Semicontext не работает - PullRequest
0 голосов
/ 04 марта 2019

Поскольку этот вопрос использует список, я хотел решить его с помощью DCG.В процессе я понял, что можно использовать полуконтекст.( DCG Primer )

Первоначальная проблема заключается в том, чтобы вернуть количество элементов в списке, но если два одинаковых элемента расположены рядом друг с другом, не увеличивайте счет.

Хотя мой код работает для некоторых тестовых случаев, он не работает для других.Это всего лишь один пункт, который терпит неудачу.При просмотре кода с помощью отладчика выясняется, что вторая переменная состояния, возвращаемый список, связана с вызовом предложения, когда я думаю, что она должна быть не связана. РЕДАКТИРОВАТЬ Решил эту часть проблемы ниже.

Я использую SWI-Prolog 8.0.

Предложение, вызывающее проблему:

count_dcg(N0,N),[C2] -->
    [C1,C2],
    { N is N0 + 1 }.

Примечание: C1 помечен как Singleton variables: [C1]

Обычно я бы изменил C1 на _, но в этом случае мне нужно указать, что первый и второй элементы, обрабатываемые в настоящее время, отличаются.Другими словами, он использует неудачу объединения в качестве защиты.

Глядя на DCG с использованием листинга / 1, выявляет использование _, которое может быть проблемой, но не уверенным.

count_dcg(C, B, A, E) :-
    A=[_, F|D],
    B is C+1,
    G=D,
    E=[F|G].

Как правильно решить проблему с помощью DCG?

См. Продолжение вопрос .


Текущий исходный код

% empty list
% No semicontext (push back) needed because last item in list.
count_dcg(N,N) --> [].

% single item in list
% No semicontext (push back) needed because only one item removed from list.
count_dcg(N0,N) -->
    [_],
    \+ [_],
    { N is N0 + 1 }.

% Semicontext (push back) needed because two items removed from list.
% Need second item to stay on list.
count_dcg(N,N),[C] -->
    [C,C].

% Semicontext (push back) needed because two items removed from list.
% Need second item to stay on list.
count_dcg(N0,N),[C2] -->
    [C1,C2],
    { N is N0 + 1 }.

count(L,N) :-
    DCG = count_dcg(0,N),
    phrase(DCG,L).

Контрольные примеры

:- begin_tests(count).

test(1,[nondet]) :-
    count([],N),
    assertion( N == 0 ).

test(2,[nondet]) :-
    count([a],N),
    assertion( N == 1 ).

test(3,[nondet]) :-
    count([a,a],N),
    assertion( N == 1 ).

test(4,[nondet]) :-
    count([a,b],N),
    assertion( N == 2 ).

test(5,[nondet]) :-
    count([b,a],N),
    assertion( N == 2 ).

test(6,[nondet]) :-
    count([a,a,b],N),
    assertion( N == 2 ).

test(7,[nondet]) :-
    count([a,b,a],N),
    assertion( N == 3 ).

test(8,[nondet]) :-
    count([b,a,a],N),
    assertion( N == 2 ).

:- end_tests(count).

Выполнение теста

?- run_tests.
% PL-Unit: count ..
ERROR: c:/question_110.pl:80:
        test 3: failed

ERROR: c:/question_110.pl:84:
        test 4: failed

ERROR: c:/question_110.pl:88:
        test 5: failed

ERROR: c:/question_110.pl:92:
        test 6: failed

ERROR: c:/question_110.pl:96:
        test 7: failed

ERROR: c:/question_110.pl:100:
        test 8: failed

 done
% 6 tests failed
% 2 tests passed
false.

РЕДАКТИРОВАТЬ 1

Понял, что нужен хвостовой вызов для двух из предикатов

% Semicontext (push back) needed because two items removed from list.
% Need second item to stay on list.
count_dcg(N0,N),[C] -->
    [C,C],
    count_dcg(N0,N).

% Semicontext (push back) needed because two items removed from list.
% Need second item to stay on list.
count_dcg(N0,N),[C2] -->
    [C1,C2],
    { 
        C1 \== C2,
        N1 is N0 + 1 
    },
    count_dcg(N1,N).

Код ещене работает, но это объясняет, почему переменная состояния была связана, когда я ожидал, что она не будет связана.


РЕДАКТИРОВАТЬ 2

Хотя не использовался полуконтекст DCG, как я надеялся, с использованием вариантаполуконтекст в качестве заглядывания, код работает.Не публикуйте это как ответ, потому что я хотел бы, чтобы в ответе либо отображался код DCG, работающий с полуконтекстом в заголовке предложения, либо объяснялся, почему это не так.

lookahead(C),[C] -->
    [C].

% empty list
% No lookahead needed because last item in list.
count_3_dcg(N,N) --> [].

% single item in list
% No lookahead  needed because only one in list.
count_3_dcg(N0,N) -->
    [_],
    \+ [_],
    { N is N0 + 1 }.

% Lookahead needed because two items in list and
% only want to remove first item.
count_3_dcg(N0,N) -->
    [C1],
    lookahead(C2),
    { C1 == C2 },
    count_3_dcg(N0,N).

% Lookahead needed because two items in list and
% only want to remove first item.
count_3_dcg(N0,N) -->
    [C1],
    lookahead(C2),
    {
        C1 \== C2,
        N1 is N0 + 1
    },
    count_3_dcg(N1,N).

count(L,N) :-
    DCG = count_3_dcg(0,N),
    phrase(DCG,L).

Выполнение теста

?- run_tests.
% PL-Unit: count ........ done
% All 8 tests passed
true.

1 Ответ

0 голосов
/ 04 марта 2019

Альтернативное решение, которое не требует откатов назад или упреждения:

count_dcg(N0,N) -->
    [C], {N1 is N0 + 1}, count_dcg(N1,N,C).
count_dcg(N,N) -->
    [].

count_dcg(N0,N,C) -->
    [C],
    count_dcg(N0,N,C).
count_dcg(N0,N,C) -->
    [C1],
    {C \== C1, N1 is N0 + 1},
    count_dcg(N1,N,C1).
count_dcg(N,N,_) -->
    [].

count(L,N) :-
    phrase(count_dcg(0,N),L).
...