Пролог: сопоставление одной или нескольких анонимных переменных - PullRequest
1 голос
/ 20 марта 2012

[_, [X, _], _] будет соответствовать списку вроде [d, [X, a], s]. Есть ли способ сопоставить его с любым шаблоном, где есть одна или несколько анонимных переменных? то есть. [[X, a], s] и [[d, a], [p, z], [X, b]] будут совпадать?

Я пытаюсь написать программу для подсчета элементов в списке, т.е. [a, a, a, b, a, b] => [[a, 4], [b, 2]] но я застрял:

listcount(L, N) :-  listcountA(LS, [], N).
listcountA([X|Tail], [? [X, B], ?], N) :- B is B+1, listcountA(Tail, [? [X,B] ?], N).
listcountA([X|Tail], AL, N) :- listcountA(Tail, [[X,0]|AL], N).

Спасибо.

Ответы [ 3 ]

2 голосов
/ 20 марта 2012

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

Некоторые примечания, которые, я надеюсь, помогут вам:

listcount (L, N): - listcountA (LS, [], N).

В Прологе предикаты идентифицируются по имени и num.of.arguments, так называемый функтор и Арити .Поэтому обычно предикаты 'service' с добавленными аргументами сохраняют одно и то же имя.

listcountA ([X | Tail], [? [X, B],?], N): - B - B +1, listcountA (Tail, [? [X, B]?], N).

B означает, что B + 1 никогда не будет успешным, вы должны использовать новую переменную.И нет никакого способа сопоставить внутри списка, используя «подстановочный знак», как вы, кажется, делаете.Вместо этого напишите предикат для поиска и обновления счетчика.

Последнее замечание: обычно пары элементов обозначаются с помощью бинарного отношения, обычно некоторого (произвольного) оператора.Например, чаще всего используется тире.

Поэтому я бы написал, что

listcount(L, Counters) :-
    listcount(L, [], Counters).

listcount([X | Tail], Counted, Counters) :-
    update(X, Counted, Updated),
    !, listcount(Tail, Updated, Counters).
listcount([], Counters, Counters).

update(X, [X - C | R], [X - S | R]) :-
    S is C + 1.
update(X, [H | T], [H | R]) :-
    update(X, T, R).
update(X, [], [X - 1]).  % X just inserted

update / 3 можно упростить, используя некоторый предикат библиотеки, «перемещающийся внутрь» рекурсии.Например, используя select / 3:

listcount([X | Tail], Counted, Counters) :-
    ( select(X - C, Counted, Without)
    ->  S is C + 1
    ;   S = 1, Without = Counted
    ),
    listcount(Tail, [X - S | Without], Counters).
listcount([], Counters, Counters).
1 голос
/ 20 марта 2012

Я предвосхищу этот пост, сказав, что если вам нравится этот ответ, рассмотрите возможность присвоения правильного ответа @chac, так как этот ответ основан на их ответах.

Вот версия, в которой также используется аккумулятор иобрабатывает переменные в списке ввода, давая вам структуру выходных терминов, которую вы запросили напрямую:

listcount(L, C) :-
    listcount(L, [], C).
listcount([], PL, PL).
listcount([X|Xs], Acc, L) :-
    select([X0,C], Acc, RAcc), 
    X == X0, !,
    NewC is C + 1,
    listcount(Xs, [[X0, NewC]|RAcc], L).
listcount([X|Xs], Acc, L) :-
    listcount(Xs, [[X, 1]|Acc], L).

Обратите внимание, что listcount/2 относится к версии на основе аккумулятора, listcount/3, которая поддерживает счет в аккумулятореи не предполагает упорядочения ввода или списка ввода с земли (именованные / помеченные переменные будут работать нормально).

0 голосов
/ 20 марта 2012

[_, [X, _], _] будут соответствовать только спискам, которые имеют 3 элемента, 1-й и 3-й могут быть атомами или списками, второй элемент должен быть списком длины 2, но я предполагаю, что вы это знаете. Он не будет соответствовать списку из 2 элементов, лучше использовать рекурсию «голова к хвосту», чтобы найти элемент и вставить его в список результатов. Вот эскиз предиката, который, я готов поспорить, не сработает, если скопировать вставить;)

% find_and_inc(+element_to_search, +list_to_search, ?result_list)
find_and_inc(E, [], [[E, 1]]);
find_and_inc(E, [[E,C]|T1], [[E,C1]|T2]) :- C1 is C+1;
find_and_inc(E, [[K,C]|T1], [[K,C]|T2]) :- find_and_inc(E, T1, T2).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...