-- |
-- 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 :: (a -> b) -> Permutation m a -> Permutation m b
fmap a -> b
f (P Maybe a
v m (Permutation m a)
p) = Maybe b -> m (Permutation m b) -> Permutation m b
forall (m :: * -> *) a.
Maybe a -> m (Permutation m a) -> Permutation m a
P (a -> b
f (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a
v) ((a -> b) -> Permutation m a -> Permutation m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f (Permutation m a -> Permutation m b)
-> m (Permutation m a) -> m (Permutation m b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (Permutation m a)
p)

instance Alternative m => Applicative (Permutation m) where
  pure :: a -> Permutation m a
pure a
value = Maybe a -> m (Permutation m a) -> Permutation m a
forall (m :: * -> *) a.
Maybe a -> m (Permutation m a) -> Permutation m a
P (a -> Maybe a
forall a. a -> Maybe a
Just a
value) m (Permutation m a)
forall (f :: * -> *) a. Alternative f => f a
empty
  lhs :: Permutation m (a -> b)
lhs@(P Maybe (a -> b)
f m (Permutation m (a -> b))
v) <*> :: Permutation m (a -> b) -> Permutation m a -> Permutation m b
<*> rhs :: Permutation m a
rhs@(P Maybe a
g m (Permutation m a)
w) = Maybe b -> m (Permutation m b) -> Permutation m b
forall (m :: * -> *) a.
Maybe a -> m (Permutation m a) -> Permutation m a
P (Maybe (a -> b)
f Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe a
g) (m (Permutation m b)
lhsAlt m (Permutation m b) -> m (Permutation m b) -> m (Permutation m b)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> m (Permutation m b)
rhsAlt)
    where
      lhsAlt :: m (Permutation m b)
lhsAlt = (Permutation m (a -> b) -> Permutation m a -> Permutation m b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Permutation m a
rhs) (Permutation m (a -> b) -> Permutation m b)
-> m (Permutation m (a -> b)) -> m (Permutation m b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (Permutation m (a -> b))
v
      rhsAlt :: m (Permutation m b)
rhsAlt = (Permutation m (a -> b)
lhs Permutation m (a -> b) -> Permutation m a -> Permutation m b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>) (Permutation m a -> Permutation m b)
-> m (Permutation m a) -> m (Permutation m b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (Permutation m a)
w
  liftA2 :: (a -> b -> c)
-> Permutation m a -> Permutation m b -> Permutation m c
liftA2 a -> b -> c
f lhs :: Permutation m a
lhs@(P Maybe a
x m (Permutation m a)
v) rhs :: Permutation m b
rhs@(P Maybe b
y m (Permutation m b)
w) = Maybe c -> m (Permutation m c) -> Permutation m c
forall (m :: * -> *) a.
Maybe a -> m (Permutation m a) -> Permutation m a
P ((a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 a -> b -> c
f Maybe a
x Maybe b
y) (m (Permutation m c)
lhsAlt m (Permutation m c) -> m (Permutation m c) -> m (Permutation m c)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> m (Permutation m c)
rhsAlt)
    where
      lhsAlt :: m (Permutation m c)
lhsAlt = (\Permutation m a
p -> (a -> b -> c)
-> Permutation m a -> Permutation m b -> Permutation m c
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 a -> b -> c
f Permutation m a
p Permutation m b
rhs) (Permutation m a -> Permutation m c)
-> m (Permutation m a) -> m (Permutation m c)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (Permutation m a)
v
      rhsAlt :: m (Permutation m c)
rhsAlt = (a -> b -> c)
-> Permutation m a -> Permutation m b -> Permutation m c
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 a -> b -> c
f Permutation m a
lhs (Permutation m b -> Permutation m c)
-> m (Permutation m b) -> m (Permutation m c)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (Permutation m b)
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 :: Permutation m a -> m a
runPermutation (P Maybe a
value m (Permutation m a)
parser) = m (Permutation m a) -> m (Maybe (Permutation m a))
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional m (Permutation m a)
parser m (Maybe (Permutation m a))
-> (Maybe (Permutation m a) -> m a) -> m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Permutation m a) -> m a
forall (f :: * -> *).
(Alternative f, Monad f) =>
Maybe (Permutation f a) -> f a
f
  where
    f :: Maybe (Permutation f a) -> f a
f Maybe (Permutation f a)
Nothing = f a -> (a -> f a) -> Maybe a -> f a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe f a
forall (f :: * -> *) a. Alternative f => f a
empty a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
value
    f (Just Permutation f a
p) = Permutation f a -> f a
forall (m :: * -> *) a.
(Alternative m, Monad m) =>
Permutation m a -> m a
runPermutation Permutation f a
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 :: m b -> Permutation m a -> m a
intercalateEffect = m () -> m b -> Permutation m a -> m a
forall (m :: * -> *) c b a.
(Alternative m, Monad m) =>
m c -> m b -> Permutation m a -> m a
run m ()
noEffect
  where
    noEffect :: m ()
noEffect = () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    run :: (Alternative m, Monad m) => m c -> m b -> Permutation m a -> m a
    run :: m c -> m b -> Permutation m a -> m a
run m c
headSep m b
tailSep (P Maybe a
value m (Permutation m a)
parser) = m (Permutation m a) -> m (Maybe (Permutation m a))
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (m c
headSep m c -> m (Permutation m a) -> m (Permutation m a)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> m (Permutation m a)
parser) m (Maybe (Permutation m a))
-> (Maybe (Permutation m a) -> m a) -> m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Permutation m a) -> m a
f
      where
        f :: Maybe (Permutation m a) -> m a
f Maybe (Permutation m a)
Nothing = m a -> (a -> m a) -> Maybe a -> m a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe m a
forall (f :: * -> *) a. Alternative f => f a
empty a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
value
        f (Just Permutation m a
p) = m b -> m b -> Permutation m a -> m a
forall (m :: * -> *) c b a.
(Alternative m, Monad m) =>
m c -> m b -> Permutation m a -> m a
run m b
tailSep m b
tailSep Permutation m a
p

-- | \"Lifts\" a parser to a permutation parser.
toPermutation ::
  Alternative m =>
  -- | Permutation component
  m a ->
  Permutation m a
toPermutation :: m a -> Permutation m a
toPermutation m a
p = Maybe a -> m (Permutation m a) -> Permutation m a
forall (m :: * -> *) a.
Maybe a -> m (Permutation m a) -> Permutation m a
P Maybe a
forall a. Maybe a
Nothing (m (Permutation m a) -> Permutation m a)
-> m (Permutation m a) -> Permutation m a
forall a b. (a -> b) -> a -> b
$ a -> Permutation m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> Permutation m a) -> m a -> m (Permutation m a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m a
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 :: a -> m a -> Permutation m a
toPermutationWithDefault a
v m a
p = Maybe a -> m (Permutation m a) -> Permutation m a
forall (m :: * -> *) a.
Maybe a -> m (Permutation m a) -> Permutation m a
P (a -> Maybe a
forall a. a -> Maybe a
Just a
v) (m (Permutation m a) -> Permutation m a)
-> m (Permutation m a) -> Permutation m a
forall a b. (a -> b) -> a -> b
$ a -> Permutation m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> Permutation m a) -> m a -> m (Permutation m a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m a
p