diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.1.0 (2024-06-01)
+* add `While` combinator
+* add `Count` combinator
+* re-add `:<|>:` re-export in `Symparsec.Parsers`
+
 ## 1.0.1 (2024-05-27)
 * add `TakeRest` combinator
 * re-add `:<|>:` combinator with more accurate behaviour clarification
diff --git a/src/Symparsec/Parser/Count.hs b/src/Symparsec/Parser/Count.hs
new file mode 100644
--- /dev/null
+++ b/src/Symparsec/Parser/Count.hs
@@ -0,0 +1,147 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+module Symparsec.Parser.Count where
+
+import Symparsec.Parser.Common
+import GHC.TypeLits hiding ( ErrorMessage(..) )
+import Singleraeh.Tuple
+import Singleraeh.List
+import Singleraeh.Either
+import Singleraeh.Natural
+import DeFun.Core
+import Data.Type.Equality
+import Unsafe.Coerce ( unsafeCoerce )
+
+type CountS s r = (Natural, [r], s)
+
+type family Count n p where
+    Count n ('PParser pCh pEnd s0) = Count' n pCh pEnd s0
+type Count' n pCh pEnd s0 =
+    'PParser (CountChSym pCh s0) (CountEndSym pEnd s0) '(n, '[], s0)
+
+type SCountS ss sr = STuple3 SNat (SList sr) ss
+
+sCount
+    :: SNat n
+    -> SParser ss sr ('PParser pCh pEnd s0)
+    -> SParser (SCountS ss sr) (SList sr) (Count' n pCh pEnd s0)
+sCount n (SParser pCh pEnd s0) =
+    SParser (sCountChSym pCh s0) (sCountEndSym pEnd s0) (STuple3 n SNil s0)
+
+instance
+  ( p ~ 'PParser pCh pEnd s0, SingParser p, KnownNat n
+  ) => SingParser (Count' n pCh pEnd s0) where
+    type PS (Count' n pCh pEnd s0) =
+          SCountS (PS ('PParser pCh pEnd s0)) (PR ('PParser pCh pEnd s0))
+    type PR (Count' n pCh pEnd s0) = SList (PR ('PParser pCh pEnd s0))
+    singParser' = sCount SNat (singParser @p)
+
+type family CountCh pCh s0 ch s where
+    CountCh pCh s0 ch '(n, rs, s) = CountCh' pCh s0 ch n rs s
+
+sCountChSym
+    :: SParserChSym  ss sr pCh
+    -> ss s0
+    -> SParserChSym (SCountS ss sr) (SList sr) (CountChSym pCh s0)
+sCountChSym pCh s0 = Lam2 $ \ch (STuple3 n rs s) ->
+    sCountCh' pCh s0 ch n rs s
+
+type family CountCh' pCh s0 ch n rs s where
+    CountCh' pCh s0 ch 0 rs s = Done (Reverse rs)
+    CountCh' pCh s0 ch n rs s = CountChN pCh ch n rs s0 (pCh @@ ch @@ s)
+
+sCountCh'
+    :: SParserChSym ss sr pCh
+    -> ss s0
+    -> SChar ch
+    -> SNat n
+    -> SList sr rs
+    -> ss s
+    -> SResult (SCountS ss sr) (SList sr) (CountCh' pCh s0 ch n rs s)
+sCountCh' pCh s0 ch n rs s =
+    case testEquality n (SNat @0) of
+      Just Refl -> SDone $ sReverse rs
+      Nothing   -> unsafeCoerce $ sCountChN pCh ch n rs s0 (pCh @@ ch @@ s)
+
+type family CountChN pCh ch n rs s0 res where
+    CountChN pCh ch n rs s0 (Cont s) = Cont '(n, rs, s)
+    CountChN pCh ch n rs s0 (Done r) = CountCh' pCh s0 ch (n-1) (r:rs) s0
+    CountChN pCh ch n rs s0 (Err  e) = Err (ECount e)
+
+sCountChN
+    :: SParserChSym ss sr pCh
+    -> SChar ch
+    -> SNat n
+    -> SList sr rs
+    -> ss s0
+    -> SResult ss sr res
+    -> SResult (SCountS ss sr) (SList sr) (CountChN pCh ch n rs s0 res)
+sCountChN pCh ch n rs s0 = \case
+  SCont s -> SCont $ STuple3 n rs s
+  SDone r -> sCountCh' pCh s0 ch (n %- SNat @1) (SCons r rs) s0
+  SErr  e -> SErr  $ eCount e
+
+type ECount e = EIn "Count" e
+eCount :: SE e -> SE (ECount e)
+eCount e = withSingE e $ singE
+
+type CountChSym
+    :: ParserChSym  s r
+    -> s
+    -> ParserChSym  (CountS s r) [r]
+data CountChSym pCh s0 f
+type instance App (CountChSym pCh s0) f = CountChSym1 pCh s0 f
+
+type CountChSym1
+    :: ParserChSym  s r
+    -> s
+    -> ParserChSym1 (CountS s r) [r]
+data CountChSym1 pCh s0 ch s
+type instance App (CountChSym1 pCh s0 ch) s = CountCh pCh s0 ch s
+
+type family CountEnd pEnd s0 s where
+    CountEnd pEnd s0 '(n, rs, s) = CountEnd' pEnd s0 n rs s
+
+type family CountEnd' pEnd s0 n rs s where
+    CountEnd' pEnd s0 0 rs s = Right (Reverse rs)
+    CountEnd' pEnd s0 n rs s = CountEndN pEnd s0 n rs (pEnd @@ s)
+
+sCountEnd'
+    :: SParserEndSym ss sr pEnd
+    -> ss s0
+    -> SNat n
+    -> SList sr rs
+    -> ss s
+    -> SResultEnd (SList sr) (CountEnd' pEnd s0 n rs s)
+sCountEnd' pEnd s0 n rs s =
+    case testEquality n (SNat @0) of
+      Just Refl -> SRight $ sReverse rs
+      Nothing   -> unsafeCoerce $ sCountEndN pEnd s0 n rs (pEnd @@ s)
+
+type family CountEndN pEnd s0 n rs res where
+    CountEndN pEnd s0 n rs (Right r) = CountEnd' pEnd s0 (n-1) (r:rs) s0
+    CountEndN pEnd s0 n rs (Left  e) = Left (ECount e)
+
+sCountEndN
+    :: SParserEndSym ss sr pEnd
+    -> ss s0
+    -> SNat n
+    -> SList sr rs
+    -> SResultEnd sr res
+    -> SResultEnd (SList sr) (CountEndN pEnd s0 n rs res)
+sCountEndN pEnd s0 n rs = \case
+  SRight r -> sCountEnd' pEnd s0 (n %- SNat @1) (SCons r rs) s0
+  SLeft  e -> SLeft $ eCount e
+
+type CountEndSym
+    :: ParserEndSym s r
+    -> s
+    -> ParserEndSym (CountS s r) [r]
+data CountEndSym pEnd s0 s
+type instance App (CountEndSym pEnd s0) s = CountEnd pEnd s0 s
+
+sCountEndSym
+    :: SParserEndSym ss              sr         pEnd
+    -> ss s0
+    -> SParserEndSym (SCountS ss sr) (SList sr) (CountEndSym pEnd s0)
+sCountEndSym pEnd s0 = Lam $ \(STuple3 n rs s) -> sCountEnd' pEnd s0 n rs s
diff --git a/src/Symparsec/Parser/While.hs b/src/Symparsec/Parser/While.hs
new file mode 100644
--- /dev/null
+++ b/src/Symparsec/Parser/While.hs
@@ -0,0 +1,72 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+module Symparsec.Parser.While where
+
+import Symparsec.Parser.Common
+import DeFun.Core
+import GHC.TypeLits
+import Singleraeh.Bool
+import Singleraeh.Either
+import Symparsec.Parser.While.Predicates
+
+-- | Run the given parser while the given character predicate succeeds.
+type family While chPred p where
+    While chPred ('PParser pCh pEnd s0) = While' chPred pCh pEnd s0
+type While' chPred pCh pEnd s0 = 'PParser (WhileChSym chPred pCh pEnd) pEnd s0
+
+sWhile
+    :: Lam SChar SBool chPred
+    -> SParser ss sr ('PParser pCh pEnd s0)
+    -> SParser ss sr (While' chPred pCh pEnd s0)
+sWhile chPred (SParser pCh pEnd s0) =
+    SParser (sWhileChSym chPred pCh pEnd) pEnd s0
+
+instance
+  ( p ~ 'PParser pCh pEnd s0, SingParser p
+  , SingChPred chPred
+  ) => SingParser (While' chPred pCh pEnd s0) where
+    type PS (While' chPred pCh pEnd s0) = PS ('PParser pCh pEnd s0)
+    type PR (While' chPred pCh pEnd s0) = PR ('PParser pCh pEnd s0)
+    singParser' = sWhile (singChPred @chPred) (singParser @p)
+
+type WhileCh chPred pCh pEnd ch s = WhileCh' pCh pEnd ch s (chPred @@ ch)
+type family WhileCh' pCh pEnd ch s res where
+    WhileCh' pCh pEnd ch s True  = pCh @@ ch @@ s
+    WhileCh' pCh pEnd ch s False = WhileCh'' (pEnd @@ s)
+
+type family WhileCh'' res where
+    WhileCh'' (Right r) = Done r
+    WhileCh'' (Left  e) = Err (EWhile e)
+
+type EWhile e = EIn "While" e
+eWhile :: SE e -> SE (EWhile e)
+eWhile e = withSingE e $ singE
+
+type WhileChSym
+    :: (Char ~> Bool)
+    -> ParserChSym  s r
+    -> ParserEndSym s r
+    -> ParserChSym  s r
+data WhileChSym chPred pCh pEnd f
+type instance App (WhileChSym chPred pCh pEnd) f = WhileChSym1 chPred pCh pEnd f
+
+type WhileChSym1
+    :: (Char ~> Bool)
+    -> ParserChSym  s r
+    -> ParserEndSym s r
+    -> ParserChSym1 s r
+data WhileChSym1 chPred pCh pEnd ch s
+type instance App (WhileChSym1 chPred pCh pEnd ch) s = WhileCh chPred pCh pEnd ch s
+
+sWhileChSym
+    :: Lam SChar SBool chPred
+    -> SParserChSym  ss sr pCh
+    -> SParserEndSym ss sr pEnd
+    -> SParserChSym  ss sr (WhileChSym chPred pCh pEnd)
+sWhileChSym chPred pCh pEnd = Lam2 $ \ch s ->
+    case chPred @@ ch of
+      STrue  -> pCh @@ ch @@ s
+      SFalse ->
+        case pEnd @@ s of
+          SRight r -> SDone r
+          SLeft  e -> SErr $ eWhile e
diff --git a/src/Symparsec/Parser/While/Predicates.hs b/src/Symparsec/Parser/While/Predicates.hs
new file mode 100644
--- /dev/null
+++ b/src/Symparsec/Parser/While/Predicates.hs
@@ -0,0 +1,193 @@
+-- | Character predicates.
+
+-- TODO for singling, I could cheat by inspecting the char value. should be
+-- faster and better. but would need a bit more checking so cba for now.
+
+module Symparsec.Parser.While.Predicates where
+
+import DeFun.Core
+import GHC.TypeLits
+import Singleraeh.Bool
+import Singleraeh.Equality ( testEqElse )
+import Unsafe.Coerce ( unsafeCoerce )
+
+class SingChPred chPred where
+    singChPred :: Lam SChar SBool chPred
+
+-- | @A-Za-z@
+type IsAlpha :: Char -> Bool
+type family IsAlpha ch where
+    IsAlpha 'a' = True
+    IsAlpha 'A' = True
+    IsAlpha 'b' = True
+    IsAlpha 'B' = True
+    IsAlpha 'c' = True
+    IsAlpha 'C' = True
+    IsAlpha 'd' = True
+    IsAlpha 'D' = True
+    IsAlpha 'e' = True
+    IsAlpha 'E' = True
+    IsAlpha 'f' = True
+    IsAlpha 'F' = True
+    IsAlpha 'g' = True
+    IsAlpha 'G' = True
+    IsAlpha 'h' = True
+    IsAlpha 'H' = True
+    IsAlpha 'i' = True
+    IsAlpha 'I' = True
+    IsAlpha 'j' = True
+    IsAlpha 'J' = True
+    IsAlpha 'k' = True
+    IsAlpha 'K' = True
+    IsAlpha 'l' = True
+    IsAlpha 'L' = True
+    IsAlpha 'm' = True
+    IsAlpha 'M' = True
+    IsAlpha 'n' = True
+    IsAlpha 'N' = True
+    IsAlpha 'o' = True
+    IsAlpha 'O' = True
+    IsAlpha 'p' = True
+    IsAlpha 'P' = True
+    IsAlpha 'q' = True
+    IsAlpha 'Q' = True
+    IsAlpha 'r' = True
+    IsAlpha 'R' = True
+    IsAlpha 's' = True
+    IsAlpha 'S' = True
+    IsAlpha 't' = True
+    IsAlpha 'T' = True
+    IsAlpha 'u' = True
+    IsAlpha 'U' = True
+    IsAlpha 'v' = True
+    IsAlpha 'V' = True
+    IsAlpha 'w' = True
+    IsAlpha 'W' = True
+    IsAlpha 'x' = True
+    IsAlpha 'X' = True
+    IsAlpha 'y' = True
+    IsAlpha 'Y' = True
+    IsAlpha 'z' = True
+    IsAlpha 'Z' = True
+    IsAlpha _   = False
+
+type IsAlphaSym :: Char ~> Bool
+data IsAlphaSym ch
+type instance App IsAlphaSym ch = IsAlpha ch
+
+sIsAlphaSym :: Lam SChar SBool IsAlphaSym
+sIsAlphaSym = Lam $ \ch ->
+      testEqElse ch (SChar @'a') STrue
+    $ testEqElse ch (SChar @'A') STrue
+    $ testEqElse ch (SChar @'b') STrue
+    $ testEqElse ch (SChar @'B') STrue
+    $ testEqElse ch (SChar @'c') STrue
+    $ testEqElse ch (SChar @'C') STrue
+    $ testEqElse ch (SChar @'d') STrue
+    $ testEqElse ch (SChar @'D') STrue
+    $ testEqElse ch (SChar @'e') STrue
+    $ testEqElse ch (SChar @'E') STrue
+    $ testEqElse ch (SChar @'f') STrue
+    $ testEqElse ch (SChar @'F') STrue
+    $ testEqElse ch (SChar @'g') STrue
+    $ testEqElse ch (SChar @'G') STrue
+    $ testEqElse ch (SChar @'h') STrue
+    $ testEqElse ch (SChar @'H') STrue
+    $ testEqElse ch (SChar @'i') STrue
+    $ testEqElse ch (SChar @'I') STrue
+    $ testEqElse ch (SChar @'j') STrue
+    $ testEqElse ch (SChar @'J') STrue
+    $ testEqElse ch (SChar @'k') STrue
+    $ testEqElse ch (SChar @'K') STrue
+    $ testEqElse ch (SChar @'l') STrue
+    $ testEqElse ch (SChar @'L') STrue
+    $ testEqElse ch (SChar @'m') STrue
+    $ testEqElse ch (SChar @'M') STrue
+    $ testEqElse ch (SChar @'n') STrue
+    $ testEqElse ch (SChar @'N') STrue
+    $ testEqElse ch (SChar @'o') STrue
+    $ testEqElse ch (SChar @'O') STrue
+    $ testEqElse ch (SChar @'p') STrue
+    $ testEqElse ch (SChar @'P') STrue
+    $ testEqElse ch (SChar @'q') STrue
+    $ testEqElse ch (SChar @'Q') STrue
+    $ testEqElse ch (SChar @'r') STrue
+    $ testEqElse ch (SChar @'R') STrue
+    $ testEqElse ch (SChar @'s') STrue
+    $ testEqElse ch (SChar @'S') STrue
+    $ testEqElse ch (SChar @'t') STrue
+    $ testEqElse ch (SChar @'T') STrue
+    $ testEqElse ch (SChar @'u') STrue
+    $ testEqElse ch (SChar @'U') STrue
+    $ testEqElse ch (SChar @'v') STrue
+    $ testEqElse ch (SChar @'V') STrue
+    $ testEqElse ch (SChar @'w') STrue
+    $ testEqElse ch (SChar @'W') STrue
+    $ testEqElse ch (SChar @'x') STrue
+    $ testEqElse ch (SChar @'X') STrue
+    $ testEqElse ch (SChar @'y') STrue
+    $ testEqElse ch (SChar @'Y') STrue
+    $ testEqElse ch (SChar @'z') STrue
+    $ testEqElse ch (SChar @'Z') STrue
+    $ unsafeCoerce SFalse
+
+instance SingChPred IsAlphaSym where singChPred = sIsAlphaSym
+
+-- | @0-9A-Fa-f@
+type IsHexDigit :: Char -> Bool
+type family IsHexDigit ch where
+    IsHexDigit '0' = True
+    IsHexDigit '1' = True
+    IsHexDigit '2' = True
+    IsHexDigit '3' = True
+    IsHexDigit '4' = True
+    IsHexDigit '5' = True
+    IsHexDigit '6' = True
+    IsHexDigit '7' = True
+    IsHexDigit '8' = True
+    IsHexDigit '9' = True
+    IsHexDigit 'a' = True
+    IsHexDigit 'A' = True
+    IsHexDigit 'b' = True
+    IsHexDigit 'B' = True
+    IsHexDigit 'c' = True
+    IsHexDigit 'C' = True
+    IsHexDigit 'd' = True
+    IsHexDigit 'D' = True
+    IsHexDigit 'e' = True
+    IsHexDigit 'E' = True
+    IsHexDigit 'f' = True
+    IsHexDigit 'F' = True
+    IsHexDigit _   = False
+
+type IsHexDigitSym :: Char ~> Bool
+data IsHexDigitSym ch
+type instance App IsHexDigitSym ch = IsHexDigit ch
+
+sIsHexDigitSym :: Lam SChar SBool IsHexDigitSym
+sIsHexDigitSym = Lam $ \ch ->
+      testEqElse ch (SChar @'0') STrue
+    $ testEqElse ch (SChar @'1') STrue
+    $ testEqElse ch (SChar @'2') STrue
+    $ testEqElse ch (SChar @'3') STrue
+    $ testEqElse ch (SChar @'4') STrue
+    $ testEqElse ch (SChar @'5') STrue
+    $ testEqElse ch (SChar @'6') STrue
+    $ testEqElse ch (SChar @'7') STrue
+    $ testEqElse ch (SChar @'8') STrue
+    $ testEqElse ch (SChar @'9') STrue
+    $ testEqElse ch (SChar @'a') STrue
+    $ testEqElse ch (SChar @'A') STrue
+    $ testEqElse ch (SChar @'b') STrue
+    $ testEqElse ch (SChar @'B') STrue
+    $ testEqElse ch (SChar @'c') STrue
+    $ testEqElse ch (SChar @'C') STrue
+    $ testEqElse ch (SChar @'d') STrue
+    $ testEqElse ch (SChar @'D') STrue
+    $ testEqElse ch (SChar @'e') STrue
+    $ testEqElse ch (SChar @'E') STrue
+    $ testEqElse ch (SChar @'f') STrue
+    $ testEqElse ch (SChar @'F') STrue
+    $ unsafeCoerce SFalse
+
+instance SingChPred IsHexDigitSym where singChPred = sIsHexDigitSym
diff --git a/src/Symparsec/Parsers.hs b/src/Symparsec/Parsers.hs
--- a/src/Symparsec/Parsers.hs
+++ b/src/Symparsec/Parsers.hs
@@ -10,7 +10,7 @@
     (:<*>:)
   ,  (:*>:)
   , (:<*:)
-  -- , (:<|>:)
+  , (:<|>:)
 
   -- * Positional
   -- $positional
@@ -20,6 +20,13 @@
   , End
   , Isolate
 
+  -- * Predicated
+  -- $predicated
+  , While, TakeWhile
+
+  -- * TODO unsorted
+  , Count
+
   -- * Basic
   -- $basic
   , Literal
@@ -42,7 +49,9 @@
 import Symparsec.Parser.End
 import Symparsec.Parser.Take
 import Symparsec.Parser.TakeRest
---import Symparsec.Parser.Or
+import Symparsec.Parser.Or
+import Symparsec.Parser.While
+import Symparsec.Parser.Count
 
 -- $binary-combinators
 -- Parsers that combine two parsers. Any parsers that have term-level parallels
@@ -51,6 +60,11 @@
 -- $positional
 -- Parsers that relate to symbol position e.g. length, end of symbol.
 
+-- $predicated
+-- Parsers that include character predicates.
+
 -- $basic
 -- Simple non-combinator parsers. Probably fundamental in some way e.g. very
 -- general or common.
+
+type TakeWhile chPred = While chPred TakeRest
diff --git a/symparsec.cabal b/symparsec.cabal
--- a/symparsec.cabal
+++ b/symparsec.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           symparsec
-version:        1.0.1
+version:        1.1.0
 synopsis:       Type level string parser combinators
 description:    Please see README.md.
 category:       Types, Data
@@ -32,6 +32,7 @@
       Symparsec
       Symparsec.Parser
       Symparsec.Parser.Common
+      Symparsec.Parser.Count
       Symparsec.Parser.End
       Symparsec.Parser.Isolate
       Symparsec.Parser.Literal
@@ -44,6 +45,8 @@
       Symparsec.Parser.Then
       Symparsec.Parser.Then.VoidLeft
       Symparsec.Parser.Then.VoidRight
+      Symparsec.Parser.While
+      Symparsec.Parser.While.Predicates
       Symparsec.Parsers
       Symparsec.Run
   other-modules:
@@ -65,8 +68,8 @@
   build-depends:
       base >=4.18 && <5
     , defun-core ==0.1.*
-    , singleraeh >=0.2.0 && <0.3
-    , type-level-show >=0.2.1 && <0.3
+    , singleraeh >=0.4.0 && <0.5
+    , type-level-show >=0.3.0 && <0.4
   default-language: GHC2021
 
 test-suite spec
@@ -91,8 +94,8 @@
   build-depends:
       base >=4.18 && <5
     , defun-core ==0.1.*
-    , singleraeh >=0.2.0 && <0.3
+    , singleraeh >=0.4.0 && <0.5
     , symparsec
-    , type-level-show >=0.2.1 && <0.3
+    , type-level-show >=0.3.0 && <0.4
     , type-spec >=0.4.0.0 && <0.5
   default-language: GHC2021
