------------------------------------------------------------------------------- |-- Module : Text.Trifecta.Parser.Perm-- Copyright : (c) Edward Kmett 2011-- (c) Paolo Martini 2007-- (c) Daan Leijen 1999-2001-- License : BSD-style-- -- Maintainer : ekmett@gmail.com-- Stability : provisional-- Portability : non-portable-- -- This module implements permutation parsers. The algorithm is described in:-- -- /Parsing Permutation Phrases,/-- by Arthur Baars, Andres Loh and Doaitse Swierstra.-- Published as a functional pearl at the Haskell Workshop 2001.-- -----------------------------------------------------------------------------{-# LANGUAGE ExistentialQuantification #-}moduleText.Trifecta.Parser.Perm(Perm,permute,(<||>),(<$$>),(<|?>),(<$?>))whereimportControl.ApplicativeimportText.Trifecta.Parser.Combinators(choice)infixl1<||>,<|?>infixl2<$$>,<$?>{---------------------------------------------------------------
Building a permutation parser
---------------------------------------------------------------}-- | The expression @perm \<||> p@ adds parser @p@ to the permutation-- parser @perm@. The parser @p@ is not allowed to accept empty input --- use the optional combinator ('<|?>') instead. Returns a-- new permutation parser that includes @p@. (<||>)::Functorm=>Permm(a->b)->ma->Permmb(<||>)permp=addpermp-- | The expression @f \<$$> p@ creates a fresh permutation parser-- consisting of parser @p@. The the final result of the permutation-- parser is the function @f@ applied to the return value of @p@. The-- parser @p@ is not allowed to accept empty input - use the optional-- combinator ('<$?>') instead.---- If the function @f@ takes more than one parameter, the type variable-- @b@ is instantiated to a functional type which combines nicely with-- the adds parser @p@ to the ('<||>') combinator. This-- results in stylized code where a permutation parser starts with a-- combining function @f@ followed by the parsers. The function @f@-- gets its parameters in the order in which the parsers are specified,-- but actual input can be in any order.(<$$>)::Functorm=>(a->b)->ma->Permmb(<$$>)fp=newPermf<||>p-- | The expression @perm \<||> (x,p)@ adds parser @p@ to the-- permutation parser @perm@. The parser @p@ is optional - if it can-- not be applied, the default value @x@ will be used instead. Returns-- a new permutation parser that includes the optional parser @p@. (<|?>)::Functorm=>Permm(a->b)->(a,ma)->Permmb(<|?>)perm(x,p)=addOptpermxp-- | The expression @f \<$?> (x,p)@ creates a fresh permutation parser-- consisting of parser @p@. The the final result of the permutation-- parser is the function @f@ applied to the return value of @p@. The-- parser @p@ is optional - if it can not be applied, the default value-- @x@ will be used instead. (<$?>)::Functorm=>(a->b)->(a,ma)->Permmb(<$?>)f(x,p)=newPermf<|?>(x,p){---------------------------------------------------------------
The permutation tree
---------------------------------------------------------------}-- | The type @Perm m a@ denotes a permutation parser that,-- when converted by the 'permute' function, parses -- using the base parsing monad @m@ and returns a value of-- type @a@ on success.---- Normally, a permutation parser is first build with special operators-- like ('<||>') and than transformed into a normal parser-- using 'permute'.dataPermma=Perm(Maybea)[Branchma]instanceFunctorm=>Functor(Permm)wherefmapf(Permxxs)=Perm(fmapfx)(fmapf<$>xs)dataBranchma=forallb.Branch(Permm(b->a))(mb)instanceFunctorm=>Functor(Branchm)wherefmapf(Branchpermp)=Branch(fmap(f.)perm)p-- | The parser @permute perm@ parses a permutation of parser described-- by @perm@. For example, suppose we want to parse a permutation of:-- an optional string of @a@'s, the character @b@ and an optional @c@.-- This can be described by:---- > test = permute (tuple <$?> ("",some (char 'a'))-- > <||> char 'b' -- > <|?> ('_',char 'c'))-- > where-- > tuple a b c = (a,b,c)-- transform a permutation tree into a normal parserpermute::Alternativem=>Permma->mapermute(Permdefxs)=choice(mapbranchxs++e)wheree=maybe[](pure.pure)defbranch(Branchpermp)=flipid<$>p<*>permuteperm-- build permutation treesnewPerm::(a->b)->Permm(a->b)newPermf=Perm(Justf)[]add::Functorm=>Permm(a->b)->ma->Permmbaddperm@(Perm_mffs)p=PermNothing(first:mapinsertfs)wherefirst=Branchpermpinsert(Branchperm'p')=Branch(add(fmapflipperm')p)p'addOpt::Functorm=>Permm(a->b)->a->ma->PermmbaddOptperm@(Permmffs)xp=Perm(fmap($x)mf)(first:mapinsertfs)wherefirst=Branchpermpinsert(Branchperm'p')=Branch(addOpt(fmapflipperm')xp)p'