diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,11 @@
 Changes
 =======
 
+0.3.2
+-----
+
+Add `msym`
+
 0.3.1
 -----
 
diff --git a/Text/Regex/Applicative.hs b/Text/Regex/Applicative.hs
--- a/Text/Regex/Applicative.hs
+++ b/Text/Regex/Applicative.hs
@@ -15,6 +15,7 @@
     ( RE
     , sym
     , psym
+    , msym
     , anySym
     , string
     , reFoldl
diff --git a/Text/Regex/Applicative/Compile.hs b/Text/Regex/Applicative/Compile.hs
--- a/Text/Regex/Applicative/Compile.hs
+++ b/Text/Regex/Applicative/Compile.hs
@@ -48,7 +48,9 @@
         Symbol i p -> \k -> [t $ nonEmptyCont k] where
           -- t :: (a -> [Thread s r]) -> Thread s r
           t k = Thread i $ \s ->
-            if p s then k s else []
+            case p s of
+              Just r -> k r
+              Nothing -> []
         App n1 n2 ->
             let a1 = compile2 n1
                 a2 = compile2 n2
@@ -95,7 +97,7 @@
         Eps -> return k
         Symbol i@(ThreadId n) p -> do
             modify $ IntMap.insert n $
-                (p, k)
+                (isJust . p, k)
             return [STransition i]
         App n1 n2 -> go n1 =<< go n2 k
         Alt n1 n2 -> (++) <$> go n1 k <*> go n2 k
diff --git a/Text/Regex/Applicative/Interface.hs b/Text/Regex/Applicative/Interface.hs
--- a/Text/Regex/Applicative/Interface.hs
+++ b/Text/Regex/Applicative/Interface.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies, GADTs #-}
+{-# LANGUAGE TypeFamilies, GADTs, TupleSections #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Text.Regex.Applicative.Interface where
 import Control.Applicative hiding (empty)
@@ -36,7 +36,7 @@
 comap f re =
   case re of
     Eps -> Eps
-    Symbol t p    -> Fmap f $ Symbol t (p . f)
+    Symbol t p    -> Symbol t (p . f)
     Alt r1 r2     -> Alt (comap f r1) (comap f r2)
     App r1 r2     -> App (comap f r1) (comap f r2)
     Fmap g r      -> Fmap g (comap f r)
@@ -46,15 +46,20 @@
 
 -- | Match and return a single symbol which satisfies the predicate
 psym :: (s -> Bool) -> RE s s
-psym p = Symbol (error "Not numbered symbol") p
+psym p = msym (\s -> if p s then Just s else Nothing)
 
+-- | Like 'psym', but allows to return a computed value instead of the
+-- original symbol
+msym :: (s -> Maybe a) -> RE s a
+msym p = Symbol (error "Not numbered symbol") p
+
 -- | Match and return the given symbol
 sym :: Eq s => s -> RE s s
 sym s = psym (s ==)
 
 -- | Match and return any single symbol
 anySym :: RE s s
-anySym = psym (const True)
+anySym = msym Just
 
 -- | Match and return the given sequence of symbols.
 --
@@ -98,7 +103,7 @@
 -- | Return matched symbols as part of the return value
 withMatched :: RE s a -> RE s (a, [s])
 withMatched Eps = flip (,) [] <$> Eps
-withMatched x@(Symbol _ _) = (id &&& pure) <$> x
+withMatched (Symbol t p) = Symbol t (\s -> (,[s]) <$> p s)
 withMatched (Alt a b) = withMatched a <|> withMatched b
 withMatched (App a b) =
     (\(f, s) (x, t) -> (f x, s ++ t)) <$>
diff --git a/Text/Regex/Applicative/Object.hs b/Text/Regex/Applicative/Object.hs
--- a/Text/Regex/Applicative/Object.hs
+++ b/Text/Regex/Applicative/Object.hs
@@ -32,7 +32,7 @@
 import qualified Text.Regex.Applicative.StateQueue as SQ
 import qualified Text.Regex.Applicative.Compile as Compile
 import Data.Maybe
-import Data.List
+import Data.Foldable as F
 import Control.Monad.Trans.State
 import Control.Applicative hiding (empty)
 
@@ -45,13 +45,13 @@
 
 -- | 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
+threads (ReObject sq) = F.toList 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
+fromThreads ts = F.foldl' (flip addThread) emptyObject ts
 
 -- | Check whether a thread is a result thread
 isResult :: Thread s r -> Bool
@@ -85,8 +85,8 @@
             case t of
                 Accept {} -> q
                 Thread _ c ->
-                    foldl' (\q x -> addThread x q) q $ c s
-        newQueue = SQ.fold accum emptyObject sq
+                    F.foldl' (\q x -> addThread x q) q $ c s
+        newQueue = F.foldl' accum emptyObject sq
     in newQueue
 
 -- | Feed a symbol into a non-result thread. It is an error to call 'stepThread'
diff --git a/Text/Regex/Applicative/Reference.hs b/Text/Regex/Applicative/Reference.hs
--- a/Text/Regex/Applicative/Reference.hs
+++ b/Text/Regex/Applicative/Reference.hs
@@ -52,7 +52,9 @@
         Eps -> return $ error "eps"
         Symbol _ p -> do
             c <- getChar
-            if p c then return c else empty
+            case p c of
+              Just r -> return r
+              Nothing -> empty
         Alt a1 a2 -> re2monad a1 <|> re2monad a2
         App a1 a2 -> re2monad a1 <*> re2monad a2
         Fmap f a -> fmap f $ re2monad a
diff --git a/Text/Regex/Applicative/StateQueue.hs b/Text/Regex/Applicative/StateQueue.hs
--- a/Text/Regex/Applicative/StateQueue.hs
+++ b/Text/Regex/Applicative/StateQueue.hs
@@ -1,25 +1,35 @@
+-- | This internal module is exposed only for testing and benchmarking. You
+-- don't need to import it.
 module Text.Regex.Applicative.StateQueue
     ( StateQueue
     , empty
     , insert
     , insertUnique
-    , fold
     , getElements
     ) where
 
 import Prelude hiding (read, lookup, replicate)
 import qualified Data.IntSet as IntSet
-import Data.List (foldl')
+import Data.Foldable as F
 
+-- | 'StateQueue' is a data structure that can efficiently insert elements
+-- (preserving their order)
+-- and check whether an element with the given 'Int' key is already in the queue.
 data StateQueue a = StateQueue
     { elements :: [a]
     , ids :: !IntSet.IntSet
     }
+    deriving (Eq,Show)
 
+instance Foldable StateQueue where
+  foldr f a = F.foldr f a . getElements
+
+-- | Get the list of all elements
 getElements :: StateQueue a -> [a]
 getElements = reverse . elements
 
 {-# INLINE empty #-}
+-- | The empty state queue
 empty :: StateQueue a
 empty = StateQueue
     { elements = []
@@ -27,8 +37,9 @@
     }
 
 {-# INLINE insert #-}
+-- | Insert an element in the state queue, unless there is already an element with the same key
 insertUnique
-    :: Int
+    :: Int -- ^ key
     -> a
     -> StateQueue a
     -> StateQueue a
@@ -39,13 +50,12 @@
                 , ids = IntSet.insert i ids
                 }
 
+-- | Insert an element in the state queue without a key.
+--
+-- Since 'insert' doesn't take a key, it won't affect any 'insertUnique'.
 insert
     :: a
     -> StateQueue a
     -> StateQueue a
 insert v sq =
     sq { elements = v : elements sq }
-
-{-# INLINE fold #-}
-fold :: (a -> x -> a) -> a -> StateQueue x -> a
-fold f acc0 sq = foldl' f acc0 (reverse $ elements sq)
diff --git a/Text/Regex/Applicative/Types.hs b/Text/Regex/Applicative/Types.hs
--- a/Text/Regex/Applicative/Types.hs
+++ b/Text/Regex/Applicative/Types.hs
@@ -57,7 +57,7 @@
 -- and returns the list of @ra@'s return values on those strings.
 data RE s a where
     Eps :: RE s ()
-    Symbol :: ThreadId -> (s -> Bool) -> RE s s
+    Symbol :: ThreadId -> (s -> Maybe a) -> RE s a
     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
diff --git a/regex-applicative.cabal b/regex-applicative.cabal
--- a/regex-applicative.cabal
+++ b/regex-applicative.cabal
@@ -1,5 +1,5 @@
 Name:                regex-applicative
-Version:             0.3.1
+Version:             0.3.2
 Synopsis:            Regex-based parsing with applicative interface
 Description:         
     regex-applicative is a Haskell library for parsing using regular expressions.
@@ -27,10 +27,10 @@
                        Text.Regex.Applicative.Object
                        Text.Regex.Applicative.Common
                        Text.Regex.Applicative.Reference
+                       Text.Regex.Applicative.StateQueue
   Other-modules:       Text.Regex.Applicative.Interface
                        Text.Regex.Applicative.Types
                        Text.Regex.Applicative.Compile
-                       Text.Regex.Applicative.StateQueue
   GHC-Options:     -O2
                    -Wall
                    -fno-warn-name-shadowing
diff --git a/tests/test.hs b/tests/test.hs
--- a/tests/test.hs
+++ b/tests/test.hs
@@ -13,6 +13,8 @@
 import Test.Tasty.SmallCheck
 import Test.Tasty.HUnit
 
+import StateQueue
+
 -- Small alphabets as SmallCheck's series
 newtype A = A { a :: Char } deriving Show
 instance Monad m => Serial m A where
@@ -173,6 +175,7 @@
                 (Just ("ta", "bc",""))
             ]
         ]
+    , stateQueueTests
     ]
     where
     t name n = localOption (SmallCheckDepth n) . testProperty name
