2013-05-07 4 views
3

Как распознать язык A^n B^n в Prolog без арифметики и для любых A, B, где A! = B?Признать язык A^n B^n в Prolog без арифметики

С известной А = а и B = B мы могли бы написать

% For each 'a' save 'b' in a list, then check 
% whether constructed list is equal to the rest of input list 

anbn(L) :- anbn(L, []). 

anbn(L, L). 

anbn([a|L],A) :- anbn(L, [b|A]). 

Для любого А и Б. имел в виду решение, начиная с

anbn(L) :- anbn(L, []). 

anbn([H|L],[]) :- anbn(L,[H]). % save an element 

anbn([H|L], [H|A]) :- anbn(L, [H,H|A]). % make sure front elements are the same 

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

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

+1

Почему вы не используете defin ite clause грамматики? –

+0

@larsmans Я попробовал решение с DCG, но требования произвольных A и B и без арифметики сделали решение не намного лучше, чем стандартная нотация. Можете ли вы показать свое решение? – 2013-05-07 11:45:45

+0

Возможно, я ошибаюсь, но a^n b^n это не обычный язык. – CapelliC

ответ

2

Edit: вернуться к исходному раствору, и приклеить к нему:

anbn(List) :- List = [] -> true; List = [A|Rest], a(Rest, A, 0). 

a([A|Rest], A, N) :- !, a(Rest, A, s(N)). 
a([B|Rest], _, N) :- b(Rest, B, N). 

b([B|Rest], B, s(N)) :- b(Rest, B, N). 
b([], _, 0). 

Это итеративный, он не создает выбор-точек, то очевидно, и это правильно, если все элементы список.

+0

работает нормально. ваш, как мой (и larsmans), принимает '[1,1,1,2,2, X]'. –

+0

@WillNess yes, а также [A, a, b, B] и так далее. Я не знаю, как решить эту проблему, не добавляя требование «nonvar». – 2013-05-07 13:03:32

+0

или, возможно, это не нуждается в решении. :) (Ответ CapelliC тоже). –

0

Я думаю, что это проще, чем:

anbn(L) :- append(As, Bs, L), maplist(ab, As, Bs). 
ab(a, b). 

EDIT: Это легко обобщается на произвольные литералов.

anbn(L) :- L = [A|_], append(As, Bs, L), maplist(ab(A), As, Bs). 
ab(A, A, B) :- A \== B. 

EDIT: после Вилл Ness отметив, что это прослушивается: то, что я имел в виду

anbn(L) :- append([A|As], [B|Bs], L), A \= B, maplist(ab(A, B), As, Bs). 
ab(A, B, A, B). 
+1

dif/2 это довольно сложная библиотека. Разумеется, сложнее реализовать, где не доступно, WRT maplist/3 – CapelliC

+0

Возможно, мы подчеркиваем слишком быстрое перемещение StackOverflow :) – CapelliC

+1

'anbn ([1,1,2,3]). 'Принимается этим кодом. –

0
anbn([]) :- !. 
anbn(L) :- L=[A|_], copy_half(L,L, Z,Z, A,_V). % Z is second half 
copy_half([A|B], [_,_|C], [V|D], Z, A,V) :- !, copy_half(B,C, D,Z, A,V). 
copy_half(Z,  [],  [], Z, A,V) :- A \== V. 

Эквивалент

anbn_verboten(L):- L = [] ; 
    length(L,N), N2 is N div 2, length(X,N2), length(Y,N2), append(X,Y,L), 
    L=[P|_], Y=[Q|_], P \= Q.`. 
7

Используйте определенный раздел грамматики.

s(_, _) --> []. 
s(A, B) --> [A], s(A, B), [B]. 

Демо:

?- phrase(s(1, 2), X). 
X = [] ; 
X = [1, 2] ; 
X = [1, 1, 2, 2] ; 
X = [1, 1, 1, 2, 2, 2] . 
+2

Очень приятно, +1. В отличие от других решений, размещенных здесь, ваша работа также корректно работает для наиболее общего запроса: '? - фраза (s (X, Y), Ls) .'. Обратите внимание, однако, что вы еще не удовлетворены требованием OP о том, чтобы 'X' и' Y' отличались. В первом правиле используйте 'dif/2'. Всегда нужно использовать интерфейс 'фраза/2' (или' фраза/3') для DCG, потому что перевод DCG на предикаты Prolog может меняться в зависимости от реализации или версии Prolog. – mat

+2

Единственное решение, которое не сгорит моими глазами. :) +1 –

+0

@mat: Я прочитал A! = B как требование, чтобы решение работало в этом случае, а не то, что оно фактически соблюдается. Однако я удалил пример использования без 'phrase/2'. –

2

Это характерно для DCGs, что голые переменные rewrapped как фраза/3 во время перевода. Чтобы можно было реализовать A^n B^n не только тогда, когда A и B являются терминалами, но и , когда A и B являются произвольными целями DCG.

Вот код для этого:

s(_,_) --> []. 
s(A,B) --> A, s(A,B), B. 

Здесь один видит перевод, который делается с помощью SWI-Prolog. Как можно видеть обнаженные переменные были преобразованы в фразу/3 цели:

?- listing. 
s(_, _, A, A). 
s(A, C, B, F) :- 
    phrase(A, B, D), 
    s(A, C, D, E), 
    phrase(C, E, F). 

Ниже приведен пример выполнения, для терминалов А и В:

?- phrase(s("alfa","beta"),X), atom_codes(Y,X). 
X = [], 
Y = '' ; 
X = [97, 108, 102, 97, 98, 101, 116, 97], 
Y = alfabeta ; 
X = [97, 108, 102, 97, 97, 108, 102, 97, 98|...], 
Y = alfaalfabetabeta ; 
X = [97, 108, 102, 97, 97, 108, 102, 97, 97|...], 
Y = alfaalfaalfabetabetabeta . 

Ниже приведен пример выполнения, для некоторых целей DCG как A и B:

bit --> "0". 
    bit --> "1". 

    ?- length(L,8), phrase(s(("(",bit),(bit,")")),L), atom_codes(R,L). 
    L = [40, 48, 40, 48, 48, 41, 48, 41], 
    R = '(0(00)0)' ; 
    L = [40, 48, 40, 48, 48, 41, 49, 41], 
    R = '(0(00)1)' ; 
    L = [40, 48, 40, 48, 49, 41, 48, 41], 
    R = '(0(01)0)' ; 
    Etc.. 

Bye