Kombinátor je predikát provádějící kompozici několika parserů, jejímž výsledkem je parser nový. Snad v každé gramatice se objevuje zřetězení, proto asi nejběžnější operací nad parsery je jejich sekvenční kompozice. Definujme tedy kombinátor pro tento účel:
% <&>>(+Parser1, +Parser2, ?Wrapper) <&>>(P1,P2,I+L):- I+L1 :-> P1, <&>>^(P2,L1,L-[]). % <&>>^(+Parser2, +LosOfP1, -ComposedLosOfP1P2) <&>>^(_,[],D-D). <&>>^(P2,[N>R|L1s],L12-D):- N+L2 :-> P2, mapListDL(fstTuple *>* (const(R) *>* sndTuple),L2,L12-D_), <&>>^(P2,L1s,D_-D).Kombinátor
<&>>
postupně aplikuje na vstup parsery a . Jejich výsledky potom zkombinuje.
Na vstup je tedy nejdříve aplikován parser . Jeho výstupem je
seznam úspěšných rozkladů délky . Ten může obsahovat několik,
jednu nebo dokonce žádnou derivaci. Jak bylo uvedeno, každá položka
tohoto seznamu se skládá z nezpracovaného zbytku vstupu a výsledku:
<&>>^
aplikuje na
každý zbytek vstupu
parser . Každou aplikací
druhého parseru na zbytek v -té položce získává nový seznam
. Následně provede zkombinování výsledků obou parserů pomocí
predikátu mapListDL
a tím vytvoří seznam . Schematicky má
položka seznamu tvar:
Predikát mapListDL
se od mapList
liší pouze tím, že jeho
výstupem je seznam v rozdílové reprezentaci. Rozdílové seznamy
,..., musí být ve výsledném seznamu zřetězeny
a právě rozdílová reprezentace nám umožní efektivní provedení této
operace.