regex-applicative 0.1.4 → 0.1.5
raw patch · 10 files changed
+378/−264 lines, 10 filesdep −vectordep ~base
Dependencies removed: vector
Dependency ranges changed: base
Files
- CHANGES.md +6/−0
- Text/Regex/Applicative.hs +7/−0
- Text/Regex/Applicative/Compile.hs +12/−6
- Text/Regex/Applicative/Implementation.hs +0/−72
- Text/Regex/Applicative/Interface.hs +133/−46
- Text/Regex/Applicative/Object.hs +134/−0
- Text/Regex/Applicative/Reference.hs +0/−73
- Text/Regex/Applicative/StateQueue.hs +32/−46
- Text/Regex/Applicative/Types.hs +49/−14
- regex-applicative.cabal +5/−7
CHANGES.md view
@@ -1,6 +1,12 @@ Changes ======= +0.1.5+-----+* Expose Object interface+* Allow matching prefixes rather than the whole string+* Add non-greedy repetitions+ 0.1.4 ----- * Completely rewrite the engine. Now it's faster and runs in constant space.
Text/Regex/Applicative.hs view
@@ -18,9 +18,16 @@ , anySym , string , reFoldl+ , Greediness(..)+ , few+ , match , (=~)+ , findFirstPrefix+ , findLongestPrefix+ , findShortestPrefix , module Control.Applicative ) where+import Text.Regex.Applicative.Types import Text.Regex.Applicative.Interface import Control.Applicative
Text/Regex/Applicative/Compile.hs view
@@ -4,7 +4,7 @@ import Text.Regex.Applicative.Types -compile :: forall a s r . Regexp s ThreadId a -> (a -> [Thread s r]) -> [Thread s r]+compile :: forall a s r . RE s a -> (a -> [Thread s r]) -> [Thread s r] compile e k = compile2 e k k -- The whole point of this module is this function, compile2, which needs to be@@ -18,7 +18,7 @@ -- -- compile2 function takes two continuations: one when the match is empty and -- one when the match is non-empty. See the "Rep" case for the reason.-compile2 :: forall a s r . Regexp s ThreadId a -> (a -> [Thread s r]) -> (a -> [Thread s r]) -> [Thread s r]+compile2 :: forall a s r . RE s a -> (a -> [Thread s r]) -> (a -> [Thread s r]) -> [Thread s r] compile2 e = case e of Eps -> \ke _kn -> ke $ error "empty"@@ -36,9 +36,15 @@ \ke kn -> a1 ke kn ++ a2 ke kn Fmap f (compile2 -> a) -> \ke kn -> a (ke . f) (kn . f) -- This is actually the point where we use the difference between- -- continuations. For the inner regexp the empty continuation is a+ -- continuations. For the inner RE the empty continuation is a -- "failing" one in order to avoid non-termination.- Rep f b (compile2 -> a) ->- let threads b ke kn =- a (\_ -> []) (\v -> let b' = f b v in threads b' kn kn) ++ ke b+ Rep g f b (compile2 -> a) ->+ let combine continue stop =+ case g of+ Greedy -> continue ++ stop+ NonGreedy -> stop ++ continue+ threads b ke kn =+ combine+ (a (\_ -> []) (\v -> let b' = f b v in threads b' kn kn))+ (ke b) in threads b
− Text/Regex/Applicative/Implementation.hs
@@ -1,72 +0,0 @@-{-# LANGUAGE GADTs, TypeFamilies, ViewPatterns, PatternGuards #-}-module Text.Regex.Applicative.Implementation (match, Regexp(..)) where-import Prelude-import Control.Applicative hiding (empty)-import Control.Monad.State hiding (foldM)-import Text.Regex.Applicative.StateQueue-import Control.Monad.ST-import Text.Regex.Applicative.Types-import Text.Regex.Applicative.Compile--fresh :: (MonadState m, StateType m ~ ThreadId) => m ThreadId-fresh = do- i <- get- put $! i+1- return i--renumber :: Regexp s i a -> (Regexp s ThreadId a, ThreadId)-renumber e = flip runState 1 $ compile e- where- compile :: Regexp s i a -> State ThreadId (Regexp s ThreadId a)- compile e =- case e of- Eps -> return Eps- Symbol _ p -> Symbol <$> fresh <*> pure p- Alt a1 a2 -> Alt <$> compile a1 <*> compile a2- App a1 a2 -> App <$> compile a1 <*> compile a2- Fmap f a -> Fmap f <$> compile a- Rep f b a -> Rep f b <$> compile a---threadId :: Thread s a -> ThreadId-threadId Accept {} = 0-threadId Thread { threadId_ = i } = i---run :: StateQueue st (Thread s r)- -> StateQueue st (Thread s r)- -> [s] -> ST st (Maybe r)-run queue _ [] = fold f Nothing queue- where f a@Just{} _ _ = return a- f Nothing _ x | Accept r <- x = return $ Just r- | otherwise = return Nothing-run queue newQueue (s:ss) = do- let accum q _ t =- case t of- Accept {} -> return q- Thread _ c ->- foldM (\q x -> tryInsert x q) q $ c s- newQueue <- fold accum newQueue queue- let veryNewQueue = clear queue- run newQueue veryNewQueue ss--tryInsert :: Thread s r -> StateQueue st (Thread s r) -> ST st (StateQueue st (Thread s r))-tryInsert t@(threadId -> ThreadId i) queue = do- alreadyPresent <- member i queue- if alreadyPresent- then return queue- else insert i t queue--match :: Regexp s a r -> [s] -> Maybe r-match r s = runST $ do- let (rr, ThreadId numStates) = renumber r- q1 <- empty numStates- q2 <- empty numStates- let threads = compile rr (\x -> [Accept x])- q1 <- foldM (\q t -> tryInsert t q) q1 threads- run q1 q2 s---- This turns out to be much faster than the standard foldM,--- because of inlining.-foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a-foldM f a l = foldr (\x k a -> f a x >>= k) return l $ a
Text/Regex/Applicative/Interface.hs view
@@ -1,67 +1,44 @@-{-# LANGUAGE Rank2Types, FlexibleInstances, TypeFamilies #-}+{-# LANGUAGE Rank2Types, FlexibleInstances, TypeFamilies, TupleSections #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} module Text.Regex.Applicative.Interface where import Control.Applicative hiding (empty) import qualified Control.Applicative import Data.Traversable import Data.String-import Text.Regex.Applicative.Implementation---- | Type of regular expressions that recognize symbols of type @s@ and--- produce a result of type @a@.------ Regular expressions can be built using 'Functor', 'Applicative' and--- 'Alternative' instances in the following natural way:------ * @f@ '<$>' @ra@ matches iff @ra@ matches, and its return value is the result--- of applying @f@ to the return value of @ra@.------ * 'pure' @x@ matches the empty string (i.e. it does not consume any symbols),--- and its return value is @x@------ * @rf@ '<*>' @ra@ matches a string iff it is a concatenation of two--- strings: one matched by @rf@ and the other matched by @ra@. The return value--- is @f a@, where @f@ and @a@ are the return values of @rf@ and @ra@--- respectively.------ * @ra@ '<|>' @rb@ matches a string which is accepted by either @ra@ or @rb@.--- It is left-biased, so if both can match, the result of @ra@ is used.------ * 'Control.Applicative.empty' is a regular expression which does not match any string.------ * 'many' @ra@ matches concatenation of zero or more strings matched by @ra@--- and returns the list of @ra@'s return values on those strings.-newtype RE s a = RE (forall i . Regexp s i a)+import Data.Maybe+import Text.Regex.Applicative.Types+import Text.Regex.Applicative.Object instance Functor (RE s) where- fmap f (RE x) = RE $ Fmap f x+ fmap f x = Fmap f x instance Applicative (RE s) where- pure x = const x <$> RE Eps- (RE a1) <*> (RE a2) = RE $ App a1 a2+ pure x = const x <$> Eps+ a1 <*> a2 = App a1 a2 instance Alternative (RE s) where- (RE a1) <|> (RE a2) = RE $ Alt a1 a2- empty = RE Eps- many (RE a) = reverse <$> RE (Rep (flip (:)) [] a)+ a1 <|> a2 = Alt a1 a2+ empty = Eps+ many a = reverse <$> Rep Greedy (flip (:)) [] a instance (char ~ Char, string ~ String) => IsString (RE char string) where fromString = string --- | Matches and returns a single symbol which satisfies the predicate+-- | Match and return a single symbol which satisfies the predicate psym :: (s -> Bool) -> RE s s-psym p = RE $ Symbol (error "Not numbered symbol") p+psym p = Symbol (error "Not numbered symbol") p --- | Matches and returns the given symbol+-- | Match and return the given symbol sym :: Eq s => s -> RE s s sym s = psym (s ==) --- | Matches and returns any single symbol+-- | Match and return any single symbol anySym :: RE s s anySym = psym (const True) --- | Matches and returns the given sequence of symbols.+-- | Match and return the given sequence of symbols. ----- Note that you there is an 'IsString' instance for regular expression, so+-- Note that there is an 'IsString' instance for regular expression, so -- if you enable the @OverloadedStrings@ language extension, you can write -- @string \"foo\"@ simply as @\"foo\"@. --@@ -76,12 +53,122 @@ string :: Eq a => [a] -> RE a [a] string = traverse sym --- | Greedily matches zero or more symbols, which are combined using the given--- folding function-reFoldl :: (b -> a -> b) -> b -> RE s a -> RE s b-reFoldl f b (RE a) = RE $ Rep f b a+-- | Match zero or more instances of the given expression, which are combined using+-- the given folding function.+--+-- 'Greediness' argument controls whether this regular expression should match+-- as many as possible ('Greedy') or as few as possible ('NonGreedy') instances+-- of the underlying expression.+reFoldl :: Greediness -> (b -> a -> b) -> b -> RE s a -> RE s b+reFoldl g f b a = Rep g f b a --- | Attempts to match a string of symbols against the regular expression+-- | Match zero or more instances of the given expression, but as+-- few of them as possible (i.e. /non-greedily/). A greedy equivalent of 'few'+-- is 'many'.+--+-- Examples:+--+-- >Text.Regex.Applicative> findFirstPrefix (few anySym <* "b") "ababab"+-- >Just ("a","abab")+-- >Text.Regex.Applicative> findFirstPrefix (many anySym <* "b") "ababab"+-- >Just ("ababa","")+few :: RE s a -> RE s [a]+few a = reverse <$> Rep NonGreedy (flip (:)) [] a++-- | @s =~ a = match a s@ (=~) :: [s] -> RE s a -> Maybe a-s =~ (RE a) = match a s+s =~ a = match a s infix 2 =~++-- | Attempt to match a string of symbols against the regular expression.+-- Note that the whole string (not just some part of it) should be matched.+--+-- Examples:+--+-- >Text.Regex.Applicative> match (sym 'a' <|> sym 'b') "a"+-- >Just 'a'+-- >Text.Regex.Applicative> match (sym 'a' <|> sym 'b') "ab"+-- >Nothing+--+match :: RE s a -> [s] -> Maybe a+match re str =+ listToMaybe $+ results $+ foldl (flip step) (compile re) str++-- | Find a string prefix which is matched by the regular expression.+--+-- Of all matching prefixes, pick one using left bias (prefer the left part of+-- '<|>' to the right part) and greediness.+--+-- This is the match which a backtracking engine (such as Perl's one) would find+-- first.+--+-- If match is found, the rest of the input is also returned.+--+-- Examples:+--+-- >Text.Regex.Applicative> findFirstPrefix ("a" <|> "ab") "abc"+-- >Just ("a","bc")+-- >Text.Regex.Applicative> findFirstPrefix ("ab" <|> "a") "abc"+-- >Just ("ab","c")+-- >Text.Regex.Applicative> findFirstPrefix "bc" "abc"+-- >Nothing+findFirstPrefix :: RE s a -> [s] -> Maybe (a, [s])+findFirstPrefix re str = go (compile re) str Nothing+ where+ walk obj [] = (obj, Nothing)+ walk obj (t:ts) =+ case getResult t of+ Just r -> (obj, Just r)+ Nothing -> walk (addThread t obj) ts++ go obj str resOld =+ case walk emptyObject $ threads obj of+ (obj', resThis) ->+ let res = ((,str) <$> resThis) <|> resOld+ in+ case str of+ [] -> res+ _ | failed obj' -> res+ (s:ss) -> go (step s obj') ss res++-- | Find the longest string prefix which is matched by the regular expression.+--+-- Submatches are still determined using left bias and greediness, so this is+-- different from POSIX semantics.+--+-- If match is found, the rest of the input is also returned.+--+-- Examples:+--+-- >Text.Regex.Applicative Data.Char> let keyword = "if"+-- >Text.Regex.Applicative Data.Char> let identifier = many $ psym isAlpha+-- >Text.Regex.Applicative Data.Char> let lexeme = (Left <$> keyword) <|> (Right <$> identifier)+-- >Text.Regex.Applicative Data.Char> findLongestPrefix lexeme "if foo"+-- >Just (Left "if"," foo")+-- >Text.Regex.Applicative Data.Char> findLongestPrefix lexeme "iffoo"+-- >Just (Right "iffoo","")+findLongestPrefix :: RE s a -> [s] -> Maybe (a, [s])+findLongestPrefix re str = go (compile re) str Nothing+ where+ go obj str resOld =+ let res = (fmap (,str) $ listToMaybe $ results obj) <|> resOld+ in+ case str of+ [] -> res+ _ | failed obj -> res+ (s:ss) -> go (step s obj) ss res++-- | Find the shortest prefix (analogous to 'findLongestPrefix')+findShortestPrefix :: RE s a -> [s] -> Maybe (a, [s])+findShortestPrefix re str = go (compile re) str+ where+ go obj str =+ case results obj of+ r : _ -> Just (r, str)+ [] ->+ case str of+ [] -> Nothing+ _ | failed obj -> Nothing+ s:ss -> go (step s obj) ss
+ Text/Regex/Applicative/Object.hs view
@@ -0,0 +1,134 @@+--------------------------------------------------------------------+-- |+-- Module : Text.Regex.Applicative.Object+-- Copyright : (c) Roman Cheplyaka+-- License : MIT+--+-- Maintainer: Roman Cheplyaka <roma@ro-che.info>+-- Stability : experimental+--+-- This is a low-level interface to the regex engine.+--------------------------------------------------------------------+{-# LANGUAGE TypeFamilies, GADTs #-}+module Text.Regex.Applicative.Object+ ( ReObject+ , compile+ , emptyObject+ , Thread+ , threads+ , failed+ , isResult+ , getResult+ , results+ , ThreadId+ , threadId+ , step+ , stepThread+ , fromThreads+ , addThread+ ) where++import Text.Regex.Applicative.Types+import qualified Text.Regex.Applicative.StateQueue as SQ+import qualified Text.Regex.Applicative.Compile as Compile+import Data.Maybe+import Control.Monad.State+import Control.Applicative hiding (empty)++-- | The state of the engine is represented as a \"regex object\" of type+-- @'ReObject' s r@, where @s@ is the type of symbols and @r@ is the+-- result type (as in the 'RE' type). Think of 'ReObject' as a collection of+-- 'Thread's ordered by priority. E.g. threads generated by the left part of+-- '<|>' come before the threads generated by the right part.+newtype ReObject s r = ReObject (SQ.StateQueue (Thread s r))++-- | List of all threads of an object. Each non-result thread has a unique id.+threads :: ReObject s r -> [Thread s r]+threads (ReObject sq) = SQ.getElements sq++-- | Create an object from a list of threads. It is recommended that all+-- threads come from the same 'ReObject', unless you know what you're doing.+-- However, it should be safe to filter out or rearrange threads.+fromThreads :: [Thread s r] -> ReObject s r+fromThreads ts = foldl (flip addThread) emptyObject ts++-- | Check whether a thread is a result thread+isResult :: Thread s r -> Bool+isResult Accept {} = True+isResult _ = False++-- | Return the result of a result thread, or 'Nothing' if it's not a result+-- thread+getResult :: Thread s r -> Maybe r+getResult (Accept r) = Just r+getResult _ = Nothing++-- | Check if the object has no threads. In that case it never will+-- produce any new threads as a result of 'step'.+failed :: ReObject s r -> Bool+failed obj = null $ threads obj++-- | Empty object (with no threads)+emptyObject :: ReObject s r+emptyObject = ReObject $ SQ.empty++-- | Extract the result values from all the result threads of an object+results :: ReObject s r -> [r]+results obj =+ mapMaybe getResult $ threads obj++-- | Feed a symbol into a regex object+step :: s -> ReObject s r -> ReObject s r+step s (ReObject sq) =+ let accum q t =+ case t of+ Accept {} -> q+ Thread _ c ->+ foldl (\q x -> addThread x q) q $ c s+ newQueue = SQ.fold accum emptyObject sq+ in newQueue++-- | Feed a symbol into a non-result thread. It is an error to call 'stepThread'+-- on a result thread.+stepThread :: s -> Thread s r -> [Thread s r]+stepThread s t =+ case t of+ Thread _ c -> c s+ Accept {} -> error "stepThread on a result"++-- | Add a thread to an object. The new thread will have lower priority than the+-- threads which are already in the object.+--+-- If a (non-result) thread with the same id already exists in the object, the+-- object is not changed.+addThread :: Thread s r -> ReObject s r -> ReObject s r+addThread t (ReObject q) =+ case t of+ Accept {} -> ReObject $ SQ.insert t q+ Thread { threadId_ = ThreadId i } -> ReObject $ SQ.insertUnique i t q++-- | Compile a regular expression into a regular expression object+compile :: RE s r -> ReObject s r+compile =+ fromThreads .+ flip Compile.compile (\x -> [Accept x]) .+ renumber++renumber :: RE s a -> RE s a+renumber e = flip evalState 1 $ go e+ where+ go :: RE s a -> State ThreadId (RE s a)+ go e =+ case e of+ Eps -> return Eps+ Symbol _ p -> Symbol <$> fresh <*> pure p+ Alt a1 a2 -> Alt <$> go a1 <*> go a2+ App a1 a2 -> App <$> go a1 <*> go a2+ Fmap f a -> Fmap f <$> go a+ Rep g f b a -> Rep g f b <$> go a++fresh :: (MonadState m, StateType m ~ ThreadId) => m ThreadId+fresh = do+ i <- get+ put $! i+1+ return i
− Text/Regex/Applicative/Reference.hs
@@ -1,73 +0,0 @@------------------------------------------------------------------------ |--- Module : Text.Regex.Applicative.Reference--- Copyright : (c) Roman Cheplyaka--- License : MIT------ Maintainer: Roman Cheplyaka <roma@ro-che.info>--- Stability : experimental------ Reference implementation (using backtracking)-----------------------------------------------------------------------{-# LANGUAGE GADTs #-}-module Text.Regex.Applicative.Reference (reference) where-import Prelude hiding (getChar)-import Text.Regex.Applicative.Implementation-import Text.Regex.Applicative.Interface-import Control.Applicative-import Control.Monad----- A simple parsing monad-newtype P s a = P { unP :: [s] -> [(a, [s])] }--instance Monad (P s) where- return x = P $ \s -> [(x, s)]- (P a) >>= k = P $ \s ->- a s >>= \(x,s) -> unP (k x) s--instance Functor (P s) where- fmap = liftM--instance Applicative (P s) where- (<*>) = ap- pure = return--instance Alternative (P s) where- empty = P $ const []- P a1 <|> P a2 = P $ \s ->- a1 s ++ a2 s--getChar :: P s s-getChar = P $ \s ->- case s of- [] -> []- c:cs -> [(c,cs)]--re2monad :: Regexp s r a -> P s a-re2monad r =- case r of- Eps -> return $ error "eps"- Symbol _ p -> do- c <- getChar- if p c then return c else empty- Alt a1 a2 -> re2monad a1 <|> re2monad a2- App a1 a2 -> re2monad a1 <*> re2monad a2- Fmap f a -> fmap f $ re2monad a- Rep f b a -> rep b- where- am = re2monad a- rep b = (do a <- am; rep $ f b a) <|> return b--runP :: P s a -> [s] -> Maybe a-runP m s = case filter (null . snd) $ unP m s of- (r, _) : _ -> Just r- _ -> Nothing---- | 'reference' @r@ @s@ should give the same results as @s@ '=~' @r@.------ However, this is not very efficient implementation and is supposed to be--- used for testing only.-reference :: RE s a -> [s] -> Maybe a-reference (RE r) s = runP (re2monad r) s
Text/Regex/Applicative/StateQueue.hs view
@@ -3,63 +3,49 @@ ( StateQueue , empty , insert- , member+ , insertUnique , fold- , clear+ , getElements ) where import Prelude hiding (read, lookup, replicate)-import Data.Vector.Mutable hiding (clear)-import Control.Monad-import Control.Monad.ST+import qualified Data.IntSet as IntSet -data IndexedValue a = IndexedValue- { ixKey :: !Int- , _ixValue :: !a+data StateQueue a = StateQueue+ { elements :: [a]+ , ids :: IntSet.IntSet } -data StateQueue s a = StateQueue- { dense :: !(MVector s (IndexedValue a))- , sparseToDense :: !(MVector s Int)- , size :: !Int- }+getElements :: StateQueue a -> [a]+getElements = reverse . elements {-# INLINE empty #-}-empty :: Int -> ST st (StateQueue st a)-empty maxSize = do- d <- replicate maxSize (IndexedValue 0 $ error "SQ: Uninitialized value")- s2d <- replicate maxSize 0- return StateQueue- { dense = d- , sparseToDense = s2d- , size = 0- }+empty :: StateQueue a+empty = StateQueue+ { elements = []+ , ids = IntSet.empty+ } {-# INLINE insert #-}-insert- :: Int -> a -> StateQueue st a- -> ST st (StateQueue st a)-insert i v sq@StateQueue { size = size } = do- write (sparseToDense sq) i size- write (dense sq) size (IndexedValue i v)- return $ sq { size = size + 1 }+insertUnique+ :: Int+ -> a+ -> StateQueue a+ -> StateQueue a+insertUnique i v sq@StateQueue {..} =+ if i `IntSet.member` ids+ then sq+ else sq { elements = v : elements+ , ids = IntSet.insert i ids+ } -{-# INLINE member #-}-member- :: Int -> StateQueue st a -> ST st Bool-member i StateQueue {..} = {-# SCC "member" #-} do- di <- read sparseToDense i- if (di >= size) then return False else do- IndexedValue { ixKey = dvKey } <- read dense di- return $ dvKey == i+insert+ :: a+ -> StateQueue a+ -> StateQueue a+insert v sq =+ sq { elements = v : elements sq } {-# INLINE fold #-}-fold :: (a -> Int -> x -> ST st a) -> a -> StateQueue st x -> ST st a-fold f acc0 sq = foldM step acc0 [0 .. size sq - 1]- where- step acc n = do- IndexedValue i v <- read (dense sq) n- f acc i v--{-# INLINE clear #-}-clear sq = sq { size = 0 }+fold :: (a -> x -> a) -> a -> StateQueue x -> a+fold f acc0 sq = foldl f acc0 (reverse $ elements sq)
Text/Regex/Applicative/Types.hs view
@@ -3,24 +3,59 @@ module Text.Regex.Applicative.Types where newtype ThreadId = ThreadId Int- deriving (Show, Eq, Ord, Num)+ deriving (Show, Eq, Ord, Num, Real, Enum, Integral) -data Thread s a+-- | A thread either is a result or corresponds to a symbol in the regular+-- expression, which is expected by that thread.+data Thread s r = Thread { threadId_ :: ThreadId- , _threadCont :: s -> [Thread s a]+ , _threadCont :: s -> [Thread s r] }- | Accept a+ | Accept r -data Regexp s i a where- Eps :: Regexp s i a- Symbol :: i -> (s -> Bool) -> Regexp s i s- Alt :: Regexp s i a -> Regexp s i a -> Regexp s i a- App :: Regexp s i (a -> b) -> Regexp s i a -> Regexp s i b- Fmap :: (a -> b) -> Regexp s i a -> Regexp s i b- Rep :: (b -> a -> b) -- folding function (like in foldl)+-- | Returns thread identifier. This will be 'Just' for ordinary threads and+-- 'Nothing' for results.+threadId :: Thread s r -> Maybe ThreadId+threadId Thread { threadId_ = i } = Just i+threadId _ = Nothing++data Greediness = Greedy | NonGreedy+ deriving (Show, Read, Eq, Ord, Enum)++-- | Type of regular expressions that recognize symbols of type @s@ and+-- produce a result of type @a@.+--+-- Regular expressions can be built using 'Functor', 'Applicative' and+-- 'Alternative' instances in the following natural way:+--+-- * @f@ '<$>' @ra@ matches iff @ra@ matches, and its return value is the result+-- of applying @f@ to the return value of @ra@.+--+-- * 'pure' @x@ matches the empty string (i.e. it does not consume any symbols),+-- and its return value is @x@+--+-- * @rf@ '<*>' @ra@ matches a string iff it is a concatenation of two+-- strings: one matched by @rf@ and the other matched by @ra@. The return value+-- is @f a@, where @f@ and @a@ are the return values of @rf@ and @ra@+-- respectively.+--+-- * @ra@ '<|>' @rb@ matches a string which is accepted by either @ra@ or @rb@.+-- It is left-biased, so if both can match, the result of @ra@ is used.+--+-- * 'Control.Applicative.empty' is a regular expression which does not match any string.+--+-- * 'many' @ra@ matches concatenation of zero or more strings matched by @ra@+-- and returns the list of @ra@'s return values on those strings.+data RE s a where+ Eps :: RE s a+ Symbol :: ThreadId -> (s -> Bool) -> RE s s+ Alt :: RE s a -> RE s a -> RE s a+ App :: RE s (a -> b) -> RE s a -> RE s b+ Fmap :: (a -> b) -> RE s a -> RE s b+ Rep :: Greediness -- repetition may be greedy or not+ -> (b -> a -> b) -- folding function (like in foldl) -> b -- the value for zero matches, and also the initial value -- for the folding function- -> Regexp s i a- -> Regexp s i b-+ -> RE s a+ -> RE s b
regex-applicative.cabal view
@@ -9,7 +9,7 @@ -- standards guiding when and how versions should be incremented. -- DO NOT FORGET TO UPDATE THE GIT TAG BELOW!!!-Version: 0.1.4+Version: 0.1.5 -- A short (one-line) description of the package. Synopsis: Regex-based parsing with applicative interface@@ -56,23 +56,21 @@ Source-repository this type: git location: git://github.com/feuerbach/regex-applicative.git- tag: v0.1.4+ tag: v0.1.5 Library -- Packages needed in order to build this package.- Build-depends: base >= 4.2 && < 4.4,+ Build-depends: base >= 4.2 && < 4.5, containers >= 0.3 && < 0.5,- monads-tf == 0.1.*,- vector == 0.7.*+ monads-tf == 0.1.* -- Modules exported by the library. Exposed-modules: Text.Regex.Applicative- Text.Regex.Applicative.Reference+ Text.Regex.Applicative.Object -- Modules not exported by this package. Other-modules: Text.Regex.Applicative.Interface- Text.Regex.Applicative.Implementation Text.Regex.Applicative.Types Text.Regex.Applicative.Compile Text.Regex.Applicative.StateQueue