diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,20 @@
+## Parser combinators 1.3.1
+
+* Compiles with [MicroHs](https://github.com/augustss/MicroHs).
+
+## Parser combinators 1.3.0
+
+* Changed the `Control.Applicative.Permutations` module to only require
+  `Applicative` and not `Monad`. This module is the least restrictive and works
+  with parsers which are not `Monad`s.
+
+* Added the `Control.Monad.Permutations` module. This module may be
+  substantially more efficient for some parsers which are `Monad`s.
+
+* Corrected how permutation parsers intercalate effects and components; parsing
+  an effect requires that a component immediately follows or else a parse error
+  will result.
+
 ## Parser combinators 1.2.1
 
 * The tests in `parser-combinators-tests` now work with Megaparsec 8.
diff --git a/Control/Applicative/Combinators.hs b/Control/Applicative/Combinators.hs
--- a/Control/Applicative/Combinators.hs
+++ b/Control/Applicative/Combinators.hs
@@ -1,3 +1,6 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE TupleSections #-}
+
 -- |
 -- Module      :  Control.Applicative.Combinators
 -- Copyright   :  © 2017–present Mark Karpov
@@ -41,50 +44,49 @@
 -- backtrack in order for the alternative branch of parsing to be tried.
 -- Thus it is the responsibility of the programmer to wrap more complex,
 -- composite parsers in @try@ to achieve correct behavior.
-
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE TupleSections #-}
-
 module Control.Applicative.Combinators
   ( -- * Re-exports from "Control.Applicative"
-    (<|>)
+    (<|>),
     -- $assocbo
-  , many
+    many,
     -- $many
-  , some
+    some,
     -- $some
-  , optional
+    optional,
     -- $optional
-  , empty
+    empty,
     -- $empty
 
     -- * Original combinators
-  , between
-  , choice
-  , count
-  , count'
-  , eitherP
-  , endBy
-  , endBy1
-  , manyTill
-  , manyTill_
-  , someTill
-  , someTill_
-  , option
-  , sepBy
-  , sepBy1
-  , sepEndBy
-  , sepEndBy1
-  , skipMany
-  , skipSome
-  , skipCount
-  , skipManyTill
-  , skipSomeTill )
+    between,
+    choice,
+    count,
+    count',
+    eitherP,
+    endBy,
+    endBy1,
+    manyTill,
+    manyTill_,
+    someTill,
+    someTill_,
+    option,
+    sepBy,
+    sepBy1,
+    sepEndBy,
+    sepEndBy1,
+    skipMany,
+    skipSome,
+    skipCount,
+    skipManyTill,
+    skipSomeTill,
+  )
 where
 
-import Control.Applicative
+-- MicroHs has @Control.Applicative.asum :: Alternative f => [f a] -> f a@
+-- so we use @Data.Foldable.asum@
+import Control.Applicative hiding (asum)
 import Control.Monad (replicateM, replicateM_)
-import Data.Foldable
+import Data.Foldable (asum)
 
 ----------------------------------------------------------------------------
 -- Re-exports from "Control.Applicative"
@@ -132,8 +134,7 @@
 -- Returns the value returned by @p@.
 --
 -- > braces = between (symbol "{") (symbol "}")
-
-between :: Applicative m => m open -> m close -> m a -> m a
+between :: (Applicative m) => m open -> m close -> m a -> m a
 between open close p = open *> p <* close
 {-# INLINE between #-}
 
@@ -141,7 +142,6 @@
 -- until one of them succeeds. Returns the value of the succeeding parser.
 --
 -- > choice = asum
-
 choice :: (Foldable f, Alternative m) => f (m a) -> m a
 choice = asum
 {-# INLINE choice #-}
@@ -153,8 +153,7 @@
 -- > count = replicateM
 --
 -- See also: 'skipCount', 'count''.
-
-count :: Applicative m => Int -> m a -> m [a]
+count :: (Applicative m) => Int -> m a -> m [a]
 count = replicateM
 {-# INLINE count #-}
 
@@ -166,21 +165,19 @@
 -- as if it were equal to zero.
 --
 -- See also: 'skipCount', 'count'.
-
-count' :: Alternative m => Int -> Int -> m a -> m [a]
+count' :: (Alternative m) => Int -> Int -> m a -> m [a]
 count' m' n' p = go m' n'
   where
     go !m !n
       | n <= 0 || m > n = pure []
-      | m > 0           = liftA2 (:) p (go (m - 1) (n - 1))
-      | otherwise       = liftA2 (:) p (go 0 (n - 1)) <|> pure []
+      | m > 0 = liftA2 (:) p (go (m - 1) (n - 1))
+      | otherwise = liftA2 (:) p (go 0 (n - 1)) <|> pure []
 {-# INLINE count' #-}
 
 -- | Combine two alternatives.
 --
 -- > eitherP a b = (Left <$> a) <|> (Right <$> b)
-
-eitherP :: Alternative m => m a -> m b -> m (Either a b)
+eitherP :: (Alternative m) => m a -> m b -> m (Either a b)
 eitherP a b = (Left <$> a) <|> (Right <$> b)
 {-# INLINE eitherP #-}
 
@@ -188,15 +185,13 @@
 -- ended by @sep@. Returns a list of values returned by @p@.
 --
 -- > cStatements = cStatement `endBy` semicolon
-
-endBy :: Alternative m => m a -> m sep -> m [a]
+endBy :: (Alternative m) => m a -> m sep -> m [a]
 endBy p sep = many (p <* sep)
 {-# INLINE endBy #-}
 
 -- | @'endBy1' p sep@ parses /one/ or more occurrences of @p@, separated and
 -- ended by @sep@. Returns a list of values returned by @p@.
-
-endBy1 :: Alternative m => m a -> m sep -> m [a]
+endBy1 :: (Alternative m) => m a -> m sep -> m [a]
 endBy1 p sep = some (p <* sep)
 {-# INLINE endBy1 #-}
 
@@ -205,8 +200,7 @@
 -- is consumed and lost. Use 'manyTill_' if you wish to keep it.
 --
 -- See also: 'skipMany', 'skipManyTill'.
-
-manyTill :: Alternative m => m a -> m end -> m [a]
+manyTill :: (Alternative m) => m a -> m end -> m [a]
 manyTill p end = go
   where
     go = ([] <$ end) <|> liftA2 (:) p go
@@ -220,11 +214,10 @@
 -- See also: 'skipMany', 'skipManyTill'.
 --
 -- @since 1.2.0
-
-manyTill_ :: Alternative m => m a -> m end -> m ([a], end)
+manyTill_ :: (Alternative m) => m a -> m end -> m ([a], end)
 manyTill_ p end = go
   where
-    go = (([],) <$> end) <|> liftA2 (\x (xs, y) -> (x:xs, y)) p go
+    go = (([],) <$> end) <|> liftA2 (\x (xs, y) -> (x : xs, y)) p go
 {-# INLINE manyTill_ #-}
 
 -- | @'someTill' p end@ works similarly to @'manyTill' p end@, but @p@
@@ -234,8 +227,7 @@
 -- > someTill p end = liftA2 (:) p (manyTill p end)
 --
 -- See also: 'skipSome', 'skipSomeTill'.
-
-someTill :: Alternative m => m a -> m end -> m [a]
+someTill :: (Alternative m) => m a -> m end -> m [a]
 someTill p end = liftA2 (:) p (manyTill p end)
 {-# INLINE someTill #-}
 
@@ -246,10 +238,9 @@
 -- See also: 'skipSome', 'skipSomeTill'.
 --
 -- @since 1.2.0
-
-someTill_ :: Alternative m => m a -> m end -> m ([a], end)
+someTill_ :: (Alternative m) => m a -> m end -> m ([a], end)
 someTill_ p end =
-  liftA2 (\x (xs, y) -> (x:xs, y)) p (manyTill_ p end)
+  liftA2 (\x (xs, y) -> (x : xs, y)) p (manyTill_ p end)
 {-# INLINE someTill_ #-}
 
 -- | @'option' x p@ tries to apply the parser @p@. If @p@ fails without
@@ -259,8 +250,7 @@
 -- > option x p = p <|> pure x
 --
 -- See also: 'optional'.
-
-option :: Alternative m => a -> m a -> m a
+option :: (Alternative m) => a -> m a -> m a
 option x p = p <|> pure x
 {-# INLINE option #-}
 
@@ -268,29 +258,25 @@
 -- @sep@. Returns a list of values returned by @p@.
 --
 -- > commaSep p = p `sepBy` comma
-
-sepBy :: Alternative m => m a -> m sep -> m [a]
+sepBy :: (Alternative m) => m a -> m sep -> m [a]
 sepBy p sep = sepBy1 p sep <|> pure []
 {-# INLINE sepBy #-}
 
 -- | @'sepBy1' p sep@ parses /one/ or more occurrences of @p@, separated by
 -- @sep@. Returns a list of values returned by @p@.
-
-sepBy1 :: Alternative m => m a -> m sep -> m [a]
+sepBy1 :: (Alternative m) => m a -> m sep -> m [a]
 sepBy1 p sep = liftA2 (:) p (many (sep *> p))
 {-# INLINE sepBy1 #-}
 
 -- | @'sepEndBy' p sep@ parses /zero/ or more occurrences of @p@, separated
 -- and optionally ended by @sep@. Returns a list of values returned by @p@.
-
-sepEndBy :: Alternative m => m a -> m sep -> m [a]
+sepEndBy :: (Alternative m) => m a -> m sep -> m [a]
 sepEndBy p sep = sepEndBy1 p sep <|> pure []
 {-# INLINE sepEndBy #-}
 
 -- | @'sepEndBy1' p sep@ parses /one/ or more occurrences of @p@, separated
 -- and optionally ended by @sep@. Returns a list of values returned by @p@.
-
-sepEndBy1 :: Alternative m => m a -> m sep -> m [a]
+sepEndBy1 :: (Alternative m) => m a -> m sep -> m [a]
 sepEndBy1 p sep = liftA2 (:) p ((sep *> sepEndBy p sep) <|> pure [])
 {-# INLINEABLE sepEndBy1 #-}
 
@@ -298,8 +284,7 @@
 -- its result.
 --
 -- See also: 'manyTill', 'skipManyTill'.
-
-skipMany :: Alternative m => m a -> m ()
+skipMany :: (Alternative m) => m a -> m ()
 skipMany p = go
   where
     go = (p *> go) <|> pure ()
@@ -309,22 +294,19 @@
 -- result.
 --
 -- See also: 'someTill', 'skipSomeTill'.
-
-skipSome :: Alternative m => m a -> m ()
+skipSome :: (Alternative m) => m a -> m ()
 skipSome p = p *> skipMany p
 {-# INLINE skipSome #-}
 
 -- | @'skipCount' n p@ parses @n@ occurrences of @p@, skipping its result.
--- If @n@ is not positive, the parser equals to @'pure' []@. Returns a list
--- of @n@ values.
+-- If @n@ is not positive, the parser equals to @'pure' ()@.
 --
 -- > skipCount = replicateM_
 --
 -- See also: 'count', 'count''.
 --
 -- @since 0.3.0
-
-skipCount :: Applicative m => Int -> m a -> m ()
+skipCount :: (Applicative m) => Int -> m a -> m ()
 skipCount = replicateM_
 {-# INLINE skipCount #-}
 
@@ -333,8 +315,7 @@
 -- then returned.
 --
 -- See also: 'manyTill', 'skipMany'.
-
-skipManyTill :: Alternative m => m a -> m end -> m end
+skipManyTill :: (Alternative m) => m a -> m end -> m end
 skipManyTill p end = go
   where
     go = end <|> (p *> go)
@@ -345,7 +326,6 @@
 -- then returned.
 --
 -- See also: 'someTill', 'skipSome'.
-
-skipSomeTill :: Alternative m => m a -> m end -> m end
+skipSomeTill :: (Alternative m) => m a -> m end -> m end
 skipSomeTill p end = p *> skipManyTill p end
 {-# INLINE skipSomeTill #-}
diff --git a/Control/Applicative/Combinators/NonEmpty.hs b/Control/Applicative/Combinators/NonEmpty.hs
--- a/Control/Applicative/Combinators/NonEmpty.hs
+++ b/Control/Applicative/Combinators/NonEmpty.hs
@@ -11,33 +11,31 @@
 -- from "Control.Applicative.Combinators".
 --
 -- @since 0.2.0
-
 module Control.Applicative.Combinators.NonEmpty
-  ( some
-  , endBy1
-  , someTill
-  , sepBy1
-  , sepEndBy1 )
+  ( some,
+    endBy1,
+    someTill,
+    sepBy1,
+    sepEndBy1,
+  )
 where
 
 import Control.Applicative hiding (some)
-import Data.List.NonEmpty (NonEmpty (..))
 import qualified Control.Applicative.Combinators as C
-import qualified Data.List.NonEmpty              as NE
+import Data.List.NonEmpty (NonEmpty (..))
+import qualified Data.List.NonEmpty as NE
 
 -- | @'some' p@ applies the parser @p@ /one/ or more times and returns a
 -- list of the values returned by @p@.
 --
 -- > word = some letter
-
-some :: Alternative m => m a -> m (NonEmpty a)
+some :: (Alternative m) => m a -> m (NonEmpty a)
 some p = NE.fromList <$> C.some p
 {-# INLINE some #-}
 
 -- | @'endBy1' p sep@ parses /one/ or more occurrences of @p@, separated and
 -- ended by @sep@. Returns a non-empty list of values returned by @p@.
-
-endBy1 :: Alternative m => m a -> m sep -> m (NonEmpty a)
+endBy1 :: (Alternative m) => m a -> m sep -> m (NonEmpty a)
 endBy1 p sep = NE.fromList <$> C.endBy1 p sep
 {-# INLINE endBy1 #-}
 
@@ -45,22 +43,19 @@
 -- should succeed at least once.
 --
 -- See also: 'C.skipSome', 'C.skipSomeTill'.
-
-someTill :: Alternative m => m a -> m end -> m (NonEmpty a)
+someTill :: (Alternative m) => m a -> m end -> m (NonEmpty a)
 someTill p end = NE.fromList <$> C.someTill p end
 {-# INLINE someTill #-}
 
 -- | @'sepBy1' p sep@ parses /one/ or more occurrences of @p@, separated by
 -- @sep@. Returns a non-empty list of values returned by @p@.
-
-sepBy1 :: Alternative m => m a -> m sep -> m (NonEmpty a)
+sepBy1 :: (Alternative m) => m a -> m sep -> m (NonEmpty a)
 sepBy1 p sep = NE.fromList <$> C.sepBy1 p sep
 {-# INLINE sepBy1 #-}
 
 -- | @'sepEndBy1' p sep@ parses /one/ or more occurrences of @p@, separated
 -- and optionally ended by @sep@. Returns a non-empty list of values returned by
 -- @p@.
-
-sepEndBy1 :: Alternative m => m a -> m sep -> m (NonEmpty a)
+sepEndBy1 :: (Alternative m) => m a -> m sep -> m (NonEmpty a)
 sepEndBy1 p sep = NE.fromList <$> C.sepEndBy1 p sep
 {-# INLINE sepEndBy1 #-}
diff --git a/Control/Applicative/Permutations.hs b/Control/Applicative/Permutations.hs
--- a/Control/Applicative/Permutations.hs
+++ b/Control/Applicative/Permutations.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE ExistentialQuantification #-}
+
 -- |
 -- Module      :  Control.Applicative.Permutations
 -- Copyright   :  © 2017–present Alex Washburn
@@ -30,8 +32,8 @@
 --
 -- For example, suppose we want to parse a permutation of: an optional
 -- string of @a@'s, the character @b@ and an optional @c@. Using a standard
--- parsing library combinator @char@, this can be described using the
--- 'Applicative' instance by:
+-- parsing library combinator @char@ (e.g. 'Text.ParserCombinators.ReadP.ReadP')
+-- this can be described using the 'Applicative' instance by:
 --
 -- > test = runPermutation $
 -- >          (,,) <$> toPermutationWithDefault ""  (some (char 'a'))
@@ -39,49 +41,56 @@
 -- >               <*> toPermutationWithDefault '_' (char 'c')
 --
 -- @since 0.2.0
-
 module Control.Applicative.Permutations
   ( -- ** Permutation type
-    Permutation
+    Permutation,
+
     -- ** Permutation evaluators
-  , runPermutation
-  , intercalateEffect
+    runPermutation,
+    intercalateEffect,
+
     -- ** Permutation constructors
-  , toPermutation
-  , toPermutationWithDefault )
+    toPermutation,
+    toPermutationWithDefault,
+  )
 where
 
 import Control.Applicative
+import Data.Function ((&))
 
 -- | An 'Applicative' wrapper-type for constructing permutation parsers.
+data Permutation m a = P !(Maybe a) [Branch m a]
 
-data Permutation m a = P !(Maybe a) (m (Permutation m a))
+data Branch m a = forall z. Branch (Permutation m (z -> a)) (m z)
 
-instance Functor m => Functor (Permutation m) where
-  fmap f (P v p) = P (f <$> v) (fmap f <$> p)
+instance (Functor m) => Functor (Permutation m) where
+  fmap f (P v bs) = P (f <$> v) (fmap f <$> bs)
 
-instance Alternative m => Applicative (Permutation m) where
+instance (Functor p) => Functor (Branch p) where
+  fmap f (Branch perm p) = Branch (fmap (f .) perm) p
+
+instance (Functor m) => Applicative (Permutation m) where
   pure value = P (Just value) empty
-  lhs@(P f v) <*> rhs@(P g w) = P (f <*> g) (lhsAlt <|> rhsAlt)
+  lhs@(P f v) <*> rhs@(P g w) = P (f <*> g) $ (ins2 <$> v) <> (ins1 <$> w)
     where
-      lhsAlt = (<*> rhs) <$> v
-      rhsAlt = (lhs <*>) <$> w
-  liftA2 f lhs@(P x v) rhs@(P y w) = P (liftA2 f x y) (lhsAlt <|> rhsAlt)
+      ins1 (Branch perm p) = Branch ((.) <$> lhs <*> perm) p
+      ins2 (Branch perm p) = Branch (flip <$> perm <*> rhs) p
+  liftA2 f lhs@(P x v) rhs@(P y w) = P (liftA2 f x y) $ (ins2 <$> v) <> (ins1 <$> w)
     where
-      lhsAlt = (\p -> liftA2 f p rhs) <$> v
-      rhsAlt = liftA2 f lhs <$> w
+      ins1 (Branch perm p) = Branch (liftA2 ((.) . f) lhs perm) p
+      ins2 (Branch perm p) = Branch (liftA2 (\b g z -> f (g z) b) rhs perm) p
 
 -- | \"Unlifts\" a permutation parser into a parser to be evaluated.
-
-runPermutation
-  :: ( Alternative m
-     , Monad m)
-  => Permutation m a -- ^ Permutation specification
-  -> m a             -- ^ Resulting base monad capable of handling the permutation
-runPermutation (P value parser) = optional parser >>= f
-   where
-      f  Nothing = maybe empty pure value
-      f (Just p) = runPermutation p
+runPermutation ::
+  (Alternative m) =>
+  -- | Permutation specification
+  Permutation m a ->
+  -- | Resulting base monad capable of handling the permutation
+  m a
+runPermutation = foldAlt f
+  where
+    -- INCORRECT   = runPerms t <*> p
+    f (Branch t p) = (&) <$> p <*> runPermutation t
 
 -- | \"Unlifts\" a permutation parser into a parser to be evaluated with an
 -- intercalated effect. Useful for separators between permutation elements.
@@ -109,41 +118,48 @@
 --       permutation.
 --     * No effects are intercalated between missing components with a
 --       default value.
-
-intercalateEffect
-  :: ( Alternative m
-     , Monad m)
-  => m b             -- ^ Effect to be intercalated between permutation components
-  -> Permutation m a -- ^ Permutation specification
-  -> m a             -- ^ Resulting base monad capable of handling the permutation
-intercalateEffect = run noEffect
-   where
-     noEffect = pure ()
+--     * If an effect is encountered after a component, another component must
+--       immediately follow the effect.
+intercalateEffect ::
+  (Alternative m) =>
+  -- | Effect to be intercalated between permutation components
+  m b ->
+  -- | Permutation specification
+  Permutation m a ->
+  -- | Resulting base applicative capable of handling the permutation
+  m a
+intercalateEffect effect = foldAlt (runBranchEff effect)
+  where
+    runPermEff :: (Alternative m) => m b -> Permutation m a -> m a
+    runPermEff eff (P v bs) =
+      eff *> foldr ((<|>) . runBranchEff eff) empty bs <|> maybe empty pure v
 
-     run :: (Alternative m, Monad m) => m c -> m b -> Permutation m a -> m a
-     run headSep tailSep (P value parser) = optional headSep >>= f
-       where
-         f  Nothing = maybe empty pure value
-         f (Just _) = optional parser >>= g
-         g  Nothing = maybe empty pure value
-         g (Just p) = run tailSep tailSep p
+    runBranchEff :: (Alternative m) => m b -> Branch m a -> m a
+    runBranchEff eff (Branch t p) = (&) <$> p <*> runPermEff eff t
 
 -- | \"Lifts\" a parser to a permutation parser.
-
-toPermutation
-  :: Alternative m
-  => m a -- ^ Permutation component
-  -> Permutation m a
-toPermutation p = P Nothing $ pure <$> p
+toPermutation ::
+  (Alternative m) =>
+  -- | Permutation component
+  m a ->
+  Permutation m a
+toPermutation = P Nothing . pure . branch
 
 -- | \"Lifts\" a parser with a default value to a permutation parser.
 --
 -- If no permutation containing the supplied parser can be parsed from the input,
 -- then the supplied default value is returned in lieu of a parse result.
+toPermutationWithDefault ::
+  (Alternative m) =>
+  -- | Default Value
+  a ->
+  -- | Permutation component
+  m a ->
+  Permutation m a
+toPermutationWithDefault v = P (Just v) . pure . branch
 
-toPermutationWithDefault
-  :: Alternative m
-  => a   -- ^ Default Value
-  -> m a -- ^ Permutation component
-  -> Permutation m a
-toPermutationWithDefault v p = P (Just v) $ pure <$> p
+branch :: (Functor m) => m a -> Branch m a
+branch = Branch $ pure id
+
+foldAlt :: (Alternative m) => (Branch m a -> m a) -> Permutation m a -> m a
+foldAlt f (P v bs) = foldr ((<|>) . f) (maybe empty pure v) bs
diff --git a/Control/Monad/Combinators.hs b/Control/Monad/Combinators.hs
--- a/Control/Monad/Combinators.hs
+++ b/Control/Monad/Combinators.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE BangPatterns #-}
+
 -- |
 -- Module      :  Control.Monad.Combinators
 -- Copyright   :  © 2017–present Mark Karpov
@@ -15,46 +17,44 @@
 -- "Control.Applicative.Combinators".
 --
 -- @since 0.4.0
-
-{-# LANGUAGE BangPatterns #-}
-
 module Control.Monad.Combinators
   ( -- * Re-exports from "Control.Applicative"
-    (C.<|>)
+    (C.<|>),
     -- $assocbo
-  , C.optional
+    C.optional,
     -- $optional
-  , C.empty
+    C.empty,
     -- $empty
 
     -- * Original combinators
-  , C.between
-  , C.choice
-  , count
-  , count'
-  , C.eitherP
-  , endBy
-  , endBy1
-  , many
-  , manyTill
-  , manyTill_
-  , some
-  , someTill
-  , someTill_
-  , C.option
-  , sepBy
-  , sepBy1
-  , sepEndBy
-  , sepEndBy1
-  , skipMany
-  , skipSome
-  , skipCount
-  , skipManyTill
-  , skipSomeTill )
+    C.between,
+    C.choice,
+    count,
+    count',
+    C.eitherP,
+    endBy,
+    endBy1,
+    many,
+    manyTill,
+    manyTill_,
+    some,
+    someTill,
+    someTill_,
+    C.option,
+    sepBy,
+    sepBy1,
+    sepEndBy,
+    sepEndBy1,
+    skipMany,
+    skipSome,
+    skipCount,
+    skipManyTill,
+    skipSomeTill,
+  )
 where
 
-import Control.Monad
 import qualified Control.Applicative.Combinators as C
+import Control.Monad
 
 ----------------------------------------------------------------------------
 -- Re-exports from "Control.Applicative"
@@ -87,8 +87,7 @@
 -- values.
 --
 -- See also: 'skipCount', 'count''.
-
-count :: Monad m => Int -> m a -> m [a]
+count :: (Monad m) => Int -> m a -> m [a]
 count n' p = go id n'
   where
     go f !n =
@@ -96,7 +95,7 @@
         then return (f [])
         else do
           x <- p
-          go (f . (x:)) (n - 1)
+          go (f . (x :)) (n - 1)
 {-# INLINE count #-}
 
 -- | @'count'' m n p@ parses from @m@ to @n@ occurrences of @p@. If @n@ is
@@ -107,8 +106,7 @@
 -- as if it were equal to zero.
 --
 -- See also: 'skipCount', 'count'.
-
-count' :: MonadPlus m => Int -> Int -> m a -> m [a]
+count' :: (MonadPlus m) => Int -> Int -> m a -> m [a]
 count' m' n' p =
   if n' > 0 && n' >= m'
     then gom id m'
@@ -118,7 +116,7 @@
       if m > 0
         then do
           x <- p
-          gom (f . (x:)) (m - 1)
+          gom (f . (x :)) (m - 1)
         else god f (if m' <= 0 then n' else n' - m')
     god f !d =
       if d > 0
@@ -126,7 +124,7 @@
           r <- C.optional p
           case r of
             Nothing -> return (f [])
-            Just  x -> god (f . (x:)) (d - 1)
+            Just x -> god (f . (x :)) (d - 1)
         else return (f [])
 {-# INLINE count' #-}
 
@@ -134,15 +132,13 @@
 -- ended by @sep@. Returns a list of values returned by @p@.
 --
 -- > cStatements = cStatement `endBy` semicolon
-
-endBy :: MonadPlus m => m a -> m sep -> m [a]
+endBy :: (MonadPlus m) => m a -> m sep -> m [a]
 endBy p sep = many (p >>= \x -> x <$ sep)
 {-# INLINE endBy #-}
 
 -- | @'endBy1' p sep@ parses /one/ or more occurrences of @p@, separated and
 -- ended by @sep@. Returns a list of values returned by @p@.
-
-endBy1 :: MonadPlus m => m a -> m sep -> m [a]
+endBy1 :: (MonadPlus m) => m a -> m sep -> m [a]
 endBy1 p sep = some (p >>= \x -> x <$ sep)
 {-# INLINE endBy1 #-}
 
@@ -150,15 +146,14 @@
 -- list of the values returned by @p@.
 --
 -- > identifier = (:) <$> letter <*> many (alphaNumChar <|> char '_')
-
-many :: MonadPlus m => m a -> m [a]
+many :: (MonadPlus m) => m a -> m [a]
 many p = go id
   where
     go f = do
       r <- C.optional p
       case r of
         Nothing -> return (f [])
-        Just  x -> go (f . (x:))
+        Just x -> go (f . (x :))
 {-# INLINE many #-}
 
 -- | @'manyTill' p end@ applies parser @p@ /zero/ or more times until parser
@@ -167,8 +162,7 @@
 -- it.
 --
 -- See also: 'skipMany', 'skipManyTill'.
-
-manyTill :: MonadPlus m => m a -> m end -> m [a]
+manyTill :: (MonadPlus m) => m a -> m end -> m [a]
 manyTill p end = fst <$> manyTill_ p end
 {-# INLINE manyTill #-}
 
@@ -180,25 +174,23 @@
 -- See also: 'skipMany', 'skipManyTill'.
 --
 -- @since 1.2.0
-
-manyTill_ :: MonadPlus m => m a -> m end -> m ([a], end)
+manyTill_ :: (MonadPlus m) => m a -> m end -> m ([a], end)
 manyTill_ p end = go id
   where
     go f = do
       done <- C.optional end
       case done of
         Just done' -> return (f [], done')
-        Nothing  -> do
+        Nothing -> do
           x <- p
-          go (f . (x:))
+          go (f . (x :))
 {-# INLINE manyTill_ #-}
 
 -- | @'some' p@ applies the parser @p@ /one/ or more times and returns a
 -- list of the values returned by @p@.
 --
 -- > word = some letter
-
-some :: MonadPlus m => m a -> m [a]
+some :: (MonadPlus m) => m a -> m [a]
 some p = liftM2 (:) p (many p)
 {-# INLINE some #-}
 
@@ -209,8 +201,7 @@
 -- > someTill p end = liftM2 (:) p (manyTill p end)
 --
 -- See also: 'skipSome', 'skipSomeTill'.
-
-someTill :: MonadPlus m => m a -> m end -> m [a]
+someTill :: (MonadPlus m) => m a -> m end -> m [a]
 someTill p end = liftM2 (:) p (manyTill p end)
 {-# INLINE someTill #-}
 
@@ -221,59 +212,54 @@
 -- See also: 'skipSome', 'skipSomeTill'.
 --
 -- @since 1.2.0
-
-someTill_ :: MonadPlus m => m a -> m end -> m ([a], end)
-someTill_ p end = liftM2 (\x (xs, y) -> (x:xs, y)) p (manyTill_ p end)
+someTill_ :: (MonadPlus m) => m a -> m end -> m ([a], end)
+someTill_ p end = liftM2 (\x (xs, y) -> (x : xs, y)) p (manyTill_ p end)
 {-# INLINE someTill_ #-}
 
 -- | @'sepBy' p sep@ parses /zero/ or more occurrences of @p@, separated by
 -- @sep@. Returns a list of values returned by @p@.
 --
 -- > commaSep p = p `sepBy` comma
-
-sepBy :: MonadPlus m => m a -> m sep -> m [a]
+sepBy :: (MonadPlus m) => m a -> m sep -> m [a]
 sepBy p sep = do
   r <- C.optional p
   case r of
     Nothing -> return []
-    Just  x -> (x:) <$> many (sep >> p)
+    Just x -> (x :) <$> many (sep >> p)
 {-# INLINE sepBy #-}
 
 -- | @'sepBy1' p sep@ parses /one/ or more occurrences of @p@, separated by
 -- @sep@. Returns a list of values returned by @p@.
-
-sepBy1 :: MonadPlus m => m a -> m sep -> m [a]
+sepBy1 :: (MonadPlus m) => m a -> m sep -> m [a]
 sepBy1 p sep = do
   x <- p
-  (x:) <$> many (sep >> p)
+  (x :) <$> many (sep >> p)
 {-# INLINE sepBy1 #-}
 
 -- | @'sepEndBy' p sep@ parses /zero/ or more occurrences of @p@, separated
 -- and optionally ended by @sep@. Returns a list of values returned by @p@.
-
-sepEndBy :: MonadPlus m => m a -> m sep -> m [a]
+sepEndBy :: (MonadPlus m) => m a -> m sep -> m [a]
 sepEndBy p sep = go id
   where
     go f = do
       r <- C.optional p
       case r of
         Nothing -> return (f [])
-        Just  x -> do
+        Just x -> do
           more <- C.option False (True <$ sep)
           if more
-            then go (f . (x:))
+            then go (f . (x :))
             else return (f [x])
 {-# INLINE sepEndBy #-}
 
 -- | @'sepEndBy1' p sep@ parses /one/ or more occurrences of @p@, separated
 -- and optionally ended by @sep@. Returns a list of values returned by @p@.
-
-sepEndBy1 :: MonadPlus m => m a -> m sep -> m [a]
+sepEndBy1 :: (MonadPlus m) => m a -> m sep -> m [a]
 sepEndBy1 p sep = do
   x <- p
   more <- C.option False (True <$ sep)
   if more
-    then (x:) <$> sepEndBy p sep
+    then (x :) <$> sepEndBy p sep
     else return [x]
 {-# INLINE sepEndBy1 #-}
 
@@ -281,8 +267,7 @@
 -- its result.
 --
 -- See also: 'manyTill', 'skipManyTill'.
-
-skipMany :: MonadPlus m => m a -> m ()
+skipMany :: (MonadPlus m) => m a -> m ()
 skipMany p = go
   where
     go = do
@@ -294,18 +279,15 @@
 -- result.
 --
 -- See also: 'someTill', 'skipSomeTill'.
-
-skipSome :: MonadPlus m => m a -> m ()
+skipSome :: (MonadPlus m) => m a -> m ()
 skipSome p = p >> skipMany p
 {-# INLINE skipSome #-}
 
 -- | @'skipCount' n p@ parses @n@ occurrences of @p@, skipping its result.
--- If @n@ is smaller or equal to zero, the parser equals to @'return' []@.
--- Returns a list of @n@ values.
+-- If @n@ is smaller or equal to zero, the parser equals to @'return' ()@.
 --
 -- See also: 'count', 'count''.
-
-skipCount :: Monad m => Int -> m a -> m ()
+skipCount :: (Monad m) => Int -> m a -> m ()
 skipCount n' p = go n'
   where
     go !n =
@@ -318,15 +300,14 @@
 -- then returned.
 --
 -- See also: 'manyTill', 'skipMany'.
-
-skipManyTill :: MonadPlus m => m a -> m end -> m end
+skipManyTill :: (MonadPlus m) => m a -> m end -> m end
 skipManyTill p end = go
   where
     go = do
       r <- C.optional end
       case r of
         Nothing -> p >> go
-        Just  x -> return x
+        Just x -> return x
 {-# INLINE skipManyTill #-}
 
 -- | @'skipSomeTill' p end@ applies the parser @p@ /one/ or more times
@@ -334,7 +315,6 @@
 -- then returned.
 --
 -- See also: 'someTill', 'skipSome'.
-
-skipSomeTill :: MonadPlus m => m a -> m end -> m end
+skipSomeTill :: (MonadPlus m) => m a -> m end -> m end
 skipSomeTill p end = p >> skipManyTill p end
 {-# INLINE skipSomeTill #-}
diff --git a/Control/Monad/Combinators/Expr.hs b/Control/Monad/Combinators/Expr.hs
--- a/Control/Monad/Combinators/Expr.hs
+++ b/Control/Monad/Combinators/Expr.hs
@@ -11,10 +11,10 @@
 -- of operators.
 --
 -- @since 1.0.0
-
 module Control.Monad.Combinators.Expr
-  ( Operator (..)
-  , makeExprParser )
+  ( Operator (..),
+    makeExprParser,
+  )
 where
 
 import Control.Monad
@@ -23,15 +23,18 @@
 -- | This data type specifies operators that work on values of type @a@. An
 -- operator is either binary infix or unary prefix or postfix. A binary
 -- operator has also an associated associativity.
-
 data Operator m a
-  = InfixN  (m (a -> a -> a)) -- ^ Non-associative infix
-  | InfixL  (m (a -> a -> a)) -- ^ Left-associative infix
-  | InfixR  (m (a -> a -> a)) -- ^ Right-associative infix
-  | Prefix  (m (a -> a))      -- ^ Prefix
-  | Postfix (m (a -> a))      -- ^ Postfix
-  | TernR   (m (m (a -> a -> a -> a)))
-    -- ^ Right-associative ternary. Right-associative means that
+  = -- | Non-associative infix
+    InfixN (m (a -> a -> a))
+  | -- | Left-associative infix
+    InfixL (m (a -> a -> a))
+  | -- | Right-associative infix
+    InfixR (m (a -> a -> a))
+  | -- | Prefix
+    Prefix (m (a -> a))
+  | -- | Postfix
+    Postfix (m (a -> a))
+  | -- | Right-associative ternary. Right-associative means that
     -- @a ? b : d ? e : f@ parsed as
     -- @a ? b : (d ? e : f)@ and not as @(a ? b : d) ? e : f@.
     --
@@ -42,6 +45,7 @@
     -- Example usage:
     --
     -- >>> TernR ((If <$ char ':') <$ char '?')
+    TernR (m (m (a -> a -> a -> a)))
 
 -- | @'makeExprParser' term table@ builds an expression parser for terms
 -- @term@ with operators from @table@, taking the associativity and
@@ -88,37 +92,38 @@
 -- > binary  name f = InfixL  (f <$ symbol name)
 -- > prefix  name f = Prefix  (f <$ symbol name)
 -- > postfix name f = Postfix (f <$ symbol name)
-
-makeExprParser :: MonadPlus m
-  => m a               -- ^ Term parser
-  -> [[Operator m a]]  -- ^ Operator table, see 'Operator'
-  -> m a               -- ^ Resulting expression parser
+makeExprParser ::
+  (MonadPlus m) =>
+  -- | Term parser
+  m a ->
+  -- | Operator table, see 'Operator'
+  [[Operator m a]] ->
+  -- | Resulting expression parser
+  m a
 makeExprParser = foldl addPrecLevel
 {-# INLINEABLE makeExprParser #-}
 
 -- | @addPrecLevel p ops@ adds the ability to parse operators in table @ops@
 -- to parser @p@.
-
-addPrecLevel :: MonadPlus m => m a -> [Operator m a] -> m a
+addPrecLevel :: (MonadPlus m) => m a -> [Operator m a] -> m a
 addPrecLevel term ops =
   term' >>= \x -> choice [ras' x, las' x, nas' x, tern' x, return x]
   where
-    (ras, las, nas, prefix, postfix, tern) = foldr splitOp ([],[],[],[],[],[]) ops
+    (ras, las, nas, prefix, postfix, tern) = foldr splitOp ([], [], [], [], [], []) ops
     term' = pTerm (choice prefix) term (choice postfix)
-    ras'  = pInfixR (choice ras) term'
-    las'  = pInfixL (choice las) term'
-    nas'  = pInfixN (choice nas) term'
-    tern' = pTernR  (choice tern) term'
+    ras' = pInfixR (choice ras) term'
+    las' = pInfixL (choice las) term'
+    nas' = pInfixN (choice nas) term'
+    tern' = pTernR (choice tern) term'
 {-# INLINEABLE addPrecLevel #-}
 
 -- | @pTerm prefix term postfix@ parses a @term@ surrounded by optional
 -- prefix and postfix unary operators. Parsers @prefix@ and @postfix@ are
 -- allowed to fail, in this case 'id' is used.
-
-pTerm :: MonadPlus m => m (a -> a) -> m a -> m (a -> a) -> m a
+pTerm :: (MonadPlus m) => m (a -> a) -> m a -> m (a -> a) -> m a
 pTerm prefix term postfix = do
-  pre  <- option id prefix
-  x    <- term
+  pre <- option id prefix
+  x <- term
   post <- option id postfix
   return . post . pre $ x
 {-# INLINE pTerm #-}
@@ -126,8 +131,7 @@
 -- | @pInfixN op p x@ parses non-associative infix operator @op@, then term
 -- with parser @p@, then returns result of the operator application on @x@
 -- and the term.
-
-pInfixN :: MonadPlus m => m (a -> a -> a) -> m a -> a -> m a
+pInfixN :: (MonadPlus m) => m (a -> a -> a) -> m a -> a -> m a
 pInfixN op p x = do
   f <- op
   y <- p
@@ -137,8 +141,7 @@
 -- | @pInfixL op p x@ parses left-associative infix operator @op@, then term
 -- with parser @p@, then returns result of the operator application on @x@
 -- and the term.
-
-pInfixL :: MonadPlus m => m (a -> a -> a) -> m a -> a -> m a
+pInfixL :: (MonadPlus m) => m (a -> a -> a) -> m a -> a -> m a
 pInfixL op p x = do
   f <- op
   y <- p
@@ -149,8 +152,7 @@
 -- | @pInfixR op p x@ parses right-associative infix operator @op@, then
 -- term with parser @p@, then returns result of the operator application on
 -- @x@ and the term.
-
-pInfixR :: MonadPlus m => m (a -> a -> a) -> m a -> a -> m a
+pInfixR :: (MonadPlus m) => m (a -> a -> a) -> m a -> a -> m a
 pInfixR op p x = do
   f <- op
   y <- p >>= \r -> pInfixR op p r <|> return r
@@ -158,8 +160,7 @@
 {-# INLINE pInfixR #-}
 
 -- | Parse the first separator of a ternary operator
-
-pTernR :: MonadPlus m => m (m (a -> a -> a -> a)) -> m a -> a -> m a
+pTernR :: (MonadPlus m) => m (m (a -> a -> a -> a)) -> m a -> a -> m a
 pTernR sep1 p x = do
   sep2 <- sep1
   y <- p >>= \r -> pTernR sep1 p r `mplus` return r
@@ -169,21 +170,20 @@
 {-# INLINE pTernR #-}
 
 type Batch m a =
-  ( [m (a -> a -> a)]
-  , [m (a -> a -> a)]
-  , [m (a -> a -> a)]
-  , [m (a -> a)]
-  , [m (a -> a)]
-  , [m (m (a -> a -> a -> a))]
+  ( [m (a -> a -> a)],
+    [m (a -> a -> a)],
+    [m (a -> a -> a)],
+    [m (a -> a)],
+    [m (a -> a)],
+    [m (m (a -> a -> a -> a))]
   )
 
 -- | A helper to separate various operators (binary, unary, and according to
 -- associativity) and return them in a tuple.
-
 splitOp :: Operator m a -> Batch m a -> Batch m a
-splitOp (InfixR  op) (r, l, n, pre, post, tern) = (op:r, l, n, pre, post, tern)
-splitOp (InfixL  op) (r, l, n, pre, post, tern) = (r, op:l, n, pre, post, tern)
-splitOp (InfixN  op) (r, l, n, pre, post, tern) = (r, l, op:n, pre, post, tern)
-splitOp (Prefix  op) (r, l, n, pre, post, tern) = (r, l, n, op:pre, post, tern)
-splitOp (Postfix op) (r, l, n, pre, post, tern) = (r, l, n, pre, op:post, tern)
-splitOp (TernR   op) (r, l, n, pre, post, tern) = (r, l, n, pre, post, op:tern)
+splitOp (InfixR op) (r, l, n, pre, post, tern) = (op : r, l, n, pre, post, tern)
+splitOp (InfixL op) (r, l, n, pre, post, tern) = (r, op : l, n, pre, post, tern)
+splitOp (InfixN op) (r, l, n, pre, post, tern) = (r, l, op : n, pre, post, tern)
+splitOp (Prefix op) (r, l, n, pre, post, tern) = (r, l, n, op : pre, post, tern)
+splitOp (Postfix op) (r, l, n, pre, post, tern) = (r, l, n, pre, op : post, tern)
+splitOp (TernR op) (r, l, n, pre, post, tern) = (r, l, n, pre, post, op : tern)
diff --git a/Control/Monad/Combinators/NonEmpty.hs b/Control/Monad/Combinators/NonEmpty.hs
--- a/Control/Monad/Combinators/NonEmpty.hs
+++ b/Control/Monad/Combinators/NonEmpty.hs
@@ -11,33 +11,31 @@
 -- from "Control.Monad.Combinators".
 --
 -- @since 0.4.0
-
 module Control.Monad.Combinators.NonEmpty
-  ( some
-  , endBy1
-  , someTill
-  , sepBy1
-  , sepEndBy1 )
+  ( some,
+    endBy1,
+    someTill,
+    sepBy1,
+    sepEndBy1,
+  )
 where
 
 import Control.Monad
-import Data.List.NonEmpty (NonEmpty (..))
 import qualified Control.Monad.Combinators as C
-import qualified Data.List.NonEmpty        as NE
+import Data.List.NonEmpty (NonEmpty (..))
+import qualified Data.List.NonEmpty as NE
 
 -- | @'some' p@ applies the parser @p@ /one/ or more times and returns a
 -- list of the values returned by @p@.
 --
 -- > word = some letter
-
-some :: MonadPlus m => m a -> m (NonEmpty a)
+some :: (MonadPlus m) => m a -> m (NonEmpty a)
 some p = NE.fromList <$> C.some p
 {-# INLINE some #-}
 
 -- | @'endBy1' p sep@ parses /one/ or more occurrences of @p@, separated and
 -- ended by @sep@. Returns a non-empty list of values returned by @p@.
-
-endBy1 :: MonadPlus m => m a -> m sep -> m (NonEmpty a)
+endBy1 :: (MonadPlus m) => m a -> m sep -> m (NonEmpty a)
 endBy1 p sep = NE.fromList <$> C.endBy1 p sep
 {-# INLINE endBy1 #-}
 
@@ -45,22 +43,19 @@
 -- should succeed at least once.
 --
 -- See also: 'C.skipSome', 'C.skipSomeTill'.
-
-someTill :: MonadPlus m => m a -> m end -> m (NonEmpty a)
+someTill :: (MonadPlus m) => m a -> m end -> m (NonEmpty a)
 someTill p end = NE.fromList <$> C.someTill p end
 {-# INLINE someTill #-}
 
 -- | @'sepBy1' p sep@ parses /one/ or more occurrences of @p@, separated by
 -- @sep@. Returns a non-empty list of values returned by @p@.
-
-sepBy1 :: MonadPlus m => m a -> m sep -> m (NonEmpty a)
+sepBy1 :: (MonadPlus m) => m a -> m sep -> m (NonEmpty a)
 sepBy1 p sep = NE.fromList <$> C.sepBy1 p sep
 {-# INLINE sepBy1 #-}
 
 -- | @'sepEndBy1' p sep@ parses /one/ or more occurrences of @p@, separated
 -- and optionally ended by @sep@. Returns a non-empty list of values returned by
 -- @p@.
-
-sepEndBy1 :: MonadPlus m => m a -> m sep -> m (NonEmpty a)
+sepEndBy1 :: (MonadPlus m) => m a -> m sep -> m (NonEmpty a)
 sepEndBy1 p sep = NE.fromList <$> C.sepEndBy1 p sep
 {-# INLINE sepEndBy1 #-}
diff --git a/Control/Monad/Permutations.hs b/Control/Monad/Permutations.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Permutations.hs
@@ -0,0 +1,104 @@
+-- |
+-- Module      :  Control.Monad.Permutations
+-- Copyright   :  © 2017–present Alex Washburn
+-- License     :  BSD 3 clause
+--
+-- Maintainer  :  Mark Karpov <markkarpov92@gmail.com>
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- This module specialized the interface to 'Monad' for potential efficiency
+-- considerations, depending on the monad the permutations are run over.
+--
+-- For a more general interface requiring only 'Applicative', and for more
+-- complete documentation, see the "Control.Applicative.Permutations" module.
+--
+-- @since 1.3.0
+module Control.Monad.Permutations
+  ( -- ** Permutation type
+    Permutation,
+
+    -- ** Permutation evaluators
+    runPermutation,
+    intercalateEffect,
+
+    -- ** Permutation constructors
+    toPermutation,
+    toPermutationWithDefault,
+  )
+where
+
+import Control.Applicative
+
+-- | An 'Applicative' wrapper-type for constructing permutation parsers.
+data Permutation m a = P !(Maybe a) (m (Permutation m a))
+
+instance (Functor m) => Functor (Permutation m) where
+  fmap f (P v p) = P (f <$> v) (fmap f <$> p)
+
+instance (Alternative m) => Applicative (Permutation m) where
+  pure value = P (Just value) empty
+  lhs@(P f v) <*> rhs@(P g w) = P (f <*> g) (lhsAlt <|> rhsAlt)
+    where
+      lhsAlt = (<*> rhs) <$> v
+      rhsAlt = (lhs <*>) <$> w
+  liftA2 f lhs@(P x v) rhs@(P y w) = P (liftA2 f x y) (lhsAlt <|> rhsAlt)
+    where
+      lhsAlt = (\p -> liftA2 f p rhs) <$> v
+      rhsAlt = liftA2 f lhs <$> w
+
+-- | \"Unlifts\" a permutation parser into a parser to be evaluated.
+runPermutation ::
+  ( Alternative m,
+    Monad m
+  ) =>
+  -- | Permutation specification
+  Permutation m a ->
+  -- | Resulting base monad capable of handling the permutation
+  m a
+runPermutation (P value parser) = optional parser >>= f
+  where
+    f Nothing = maybe empty pure value
+    f (Just p) = runPermutation p
+
+-- | \"Unlifts\" a permutation parser into a parser to be evaluated with an
+-- intercalated effect. Useful for separators between permutation elements.
+intercalateEffect ::
+  ( Alternative m,
+    Monad m
+  ) =>
+  -- | Effect to be intercalated between permutation components
+  m b ->
+  -- | Permutation specification
+  Permutation m a ->
+  -- | Resulting base monad capable of handling the permutation
+  m a
+intercalateEffect = run noEffect
+  where
+    noEffect = pure ()
+    run :: (Alternative m, Monad m) => m c -> m b -> Permutation m a -> m a
+    run headSep tailSep (P value parser) = optional (headSep *> parser) >>= f
+      where
+        f Nothing = maybe empty pure value
+        f (Just p) = run tailSep tailSep p
+
+-- | \"Lifts\" a parser to a permutation parser.
+toPermutation ::
+  (Alternative m) =>
+  -- | Permutation component
+  m a ->
+  Permutation m a
+toPermutation p = P Nothing $ pure <$> p
+
+-- | \"Lifts\" a parser with a default value to a permutation parser.
+--
+-- If no permutation containing the supplied parser can be parsed from the input,
+-- then the supplied default value is returned in lieu of a parse result.
+toPermutationWithDefault ::
+  (Alternative m) =>
+  -- | Default Value
+  a ->
+  -- | Permutation component
+  m a ->
+  Permutation m a
+toPermutationWithDefault v p = P (Just v) $ pure <$> p
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 [![Hackage](https://img.shields.io/hackage/v/parser-combinators.svg?style=flat)](https://hackage.haskell.org/package/parser-combinators)
 [![Stackage Nightly](http://stackage.org/package/parser-combinators/badge/nightly)](http://stackage.org/nightly/package/parser-combinators)
 [![Stackage LTS](http://stackage.org/package/parser-combinators/badge/lts)](http://stackage.org/lts/package/parser-combinators)
-[![Build Status](https://travis-ci.org/mrkkrp/parser-combinators.svg?branch=master)](https://travis-ci.org/mrkkrp/parser-combinators)
+[![CI](https://github.com/mrkkrp/parser-combinators/actions/workflows/ci.yaml/badge.svg)](https://github.com/mrkkrp/parser-combinators/actions/workflows/ci.yaml)
 
 The package provides common parser combinators defined in terms of
 `Applicative` and `Alternative` without any dependencies but `base`. There
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Main (main) where
-
-import Distribution.Simple
-
-main :: IO ()
-main = defaultMain
diff --git a/parser-combinators.cabal b/parser-combinators.cabal
--- a/parser-combinators.cabal
+++ b/parser-combinators.cabal
@@ -1,45 +1,54 @@
-name:                 parser-combinators
-version:              1.2.1
-cabal-version:        1.18
-tested-with:          GHC==8.4.4, GHC==8.6.5, GHC==8.8.1
-license:              BSD3
-license-file:         LICENSE.md
-author:               Mark Karpov <markkarpov92@gmail.com>
-                      Alex Washburn <github@recursion.ninja>
-maintainer:           Mark Karpov <markkarpov92@gmail.com>
-homepage:             https://github.com/mrkkrp/parser-combinators
-bug-reports:          https://github.com/mrkkrp/parser-combinators/issues
-category:             Parsing
-synopsis:             Lightweight package providing commonly useful parser combinators
-build-type:           Simple
-description:          Lightweight package providing commonly useful parser combinators.
-extra-doc-files:      CHANGELOG.md
-                    , README.md
+cabal-version:   2.4
+name:            parser-combinators
+version:         1.3.1
+license:         BSD-3-Clause
+license-file:    LICENSE.md
+maintainer:      Mark Karpov <markkarpov92@gmail.com>
+author:
+    Mark Karpov <markkarpov92@gmail.com>
+    Alex Washburn <github@recursion.ninja>
 
+tested-with:     ghc ==9.8.4 ghc ==9.10.3 ghc ==9.12.1
+homepage:        https://github.com/mrkkrp/parser-combinators
+bug-reports:     https://github.com/mrkkrp/parser-combinators/issues
+synopsis:
+    Lightweight package providing commonly useful parser combinators
+
+description:
+    Lightweight package providing commonly useful parser combinators.
+
+category:        Parsing
+build-type:      Simple
+extra-doc-files:
+    CHANGELOG.md
+    README.md
+
 source-repository head
-  type:               git
-  location:           https://github.com/mrkkrp/parser-combinators.git
+    type:     git
+    location: https://github.com/mrkkrp/parser-combinators.git
 
 flag dev
-  description:        Turn on development settings.
-  manual:             True
-  default:            False
+    description: Turn on development settings.
+    default:     False
+    manual:      True
 
 library
-  build-depends:      base             >= 4.11 && < 5.0
-  exposed-modules:    Control.Applicative.Combinators
-                    , Control.Applicative.Combinators.NonEmpty
-                    , Control.Applicative.Permutations
-                    , Control.Monad.Combinators
-                    , Control.Monad.Combinators.Expr
-                    , Control.Monad.Combinators.NonEmpty
-  if flag(dev)
-    ghc-options:      -Wall -Werror
-  else
-    ghc-options:      -O2 -Wall
-  if flag(dev)
-    ghc-options:      -Wcompat
-                      -Wincomplete-record-updates
-                      -Wincomplete-uni-patterns
-                      -Wnoncanonical-monad-instances
-  default-language:   Haskell2010
+    exposed-modules:
+        Control.Applicative.Combinators
+        Control.Applicative.Combinators.NonEmpty
+        Control.Applicative.Permutations
+        Control.Monad.Combinators
+        Control.Monad.Combinators.Expr
+        Control.Monad.Combinators.NonEmpty
+        Control.Monad.Permutations
+
+    default-language: Haskell2010
+    build-depends:    base >=4.15 && <5
+
+    if flag(dev)
+        ghc-options:
+            -Wall -Werror -Wredundant-constraints -Wpartial-fields
+            -Wunused-packages
+
+    else
+        ghc-options: -O2 -Wall
