{-# OPTIONS_HADDOCK not-home #-}
module Control.Effect.Type.Split where

import Control.Effect.Internal.Union
import Control.Monad.Trans
import Control.Monad.Trans.Reader
import qualified Control.Monad.Trans.State.Lazy    as LSt
import qualified Control.Monad.Trans.State.Strict  as SSt
import qualified Control.Monad.Trans.Writer.Lazy   as LWr
import qualified Control.Monad.Trans.Writer.Strict as SWr
import qualified Control.Monad.Trans.Writer.CPS    as CPSWr

-- | An effect for splitting a nondeterministic computation
-- into its head and tail.
--
-- __'Split' is typically used as a primitive effect.__
-- If you define a 'Control.Effect.Carrier' that relies on a novel
-- non-trivial monad transformer, then you need to make
-- a @'ThreadsEff'@ instance for that monad transformer
-- to lift 'Split' (if possible).
--
-- The following threading constraints accept 'Split':
--
-- * 'Control.Effect.ReaderThreads'
-- * 'Control.Effect.State.StateThreads'
-- * 'Control.Effect.State.StateLazyThreads'
-- * 'Control.Effect.Writer.WriterThreads'
-- * 'Control.Effect.Writer.WriterLazyThreads'
data Split :: Effect where
  Split :: (Maybe (a, m a) -> b) -> m a -> Split m b

instance ThreadsEff (ReaderT s) Split where
  threadEff :: (forall x. Split m x -> m x)
-> Split (ReaderT s m) a -> ReaderT s m a
threadEff forall x. Split m x -> m x
alg (Split Maybe (a, ReaderT s m a) -> a
c ReaderT s m a
m) = (s -> m a) -> ReaderT s m a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT ((s -> m a) -> ReaderT s m a) -> (s -> m a) -> ReaderT s m a
forall a b. (a -> b) -> a -> b
$ \s
s ->
    Split m a -> m a
forall x. Split m x -> m x
alg (Split m a -> m a) -> Split m a -> m a
forall a b. (a -> b) -> a -> b
$ (Maybe (a, m a) -> a) -> m a -> Split m a
forall a (m :: * -> *) b. (Maybe (a, m a) -> b) -> m a -> Split m b
Split (Maybe (a, ReaderT s m a) -> a
c (Maybe (a, ReaderT s m a) -> a)
-> (Maybe (a, m a) -> Maybe (a, ReaderT s m a))
-> Maybe (a, m a)
-> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (((a, m a) -> (a, ReaderT s m a))
-> Maybe (a, m a) -> Maybe (a, ReaderT s m a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((a, m a) -> (a, ReaderT s m a))
 -> Maybe (a, m a) -> Maybe (a, ReaderT s m a))
-> ((m a -> ReaderT s m a) -> (a, m a) -> (a, ReaderT s m a))
-> (m a -> ReaderT s m a)
-> Maybe (a, m a)
-> Maybe (a, ReaderT s m a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (m a -> ReaderT s m a) -> (a, m a) -> (a, ReaderT s m a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) m a -> ReaderT s m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift) (ReaderT s m a -> s -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT s m a
m s
s)
  {-# INLINE threadEff #-}

instance ThreadsEff (LSt.StateT s) Split where
  threadEff :: (forall x. Split m x -> m x)
-> Split (StateT s m) a -> StateT s m a
threadEff forall x. Split m x -> m x
alg (Split Maybe (a, StateT s m a) -> a
c StateT s m a
m) = (s -> m (a, s)) -> StateT s m a
forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
LSt.StateT ((s -> m (a, s)) -> StateT s m a)
-> (s -> m (a, s)) -> StateT s m a
forall a b. (a -> b) -> a -> b
$ \s
s ->
    Split m (a, s) -> m (a, s)
forall x. Split m x -> m x
alg (Split m (a, s) -> m (a, s)) -> Split m (a, s) -> m (a, s)
forall a b. (a -> b) -> a -> b
$
      (Maybe ((a, s), m (a, s)) -> (a, s)) -> m (a, s) -> Split m (a, s)
forall a (m :: * -> *) b. (Maybe (a, m a) -> b) -> m a -> Split m b
Split
        ((a, s)
-> (((a, s), m (a, s)) -> (a, s))
-> Maybe ((a, s), m (a, s))
-> (a, s)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
          (Maybe (a, StateT s m a) -> a
c Maybe (a, StateT s m a)
forall a. Maybe a
Nothing, s
s)
          (\ ~( ~(a
a, s
s'), m (a, s)
m') ->
             (Maybe (a, StateT s m a) -> a
c (Maybe (a, StateT s m a) -> a) -> Maybe (a, StateT s m a) -> a
forall a b. (a -> b) -> a -> b
$ (a, StateT s m a) -> Maybe (a, StateT s m a)
forall a. a -> Maybe a
Just (a
a, (s -> m (a, s)) -> StateT s m a
forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
LSt.StateT ((s -> m (a, s)) -> StateT s m a)
-> (s -> m (a, s)) -> StateT s m a
forall a b. (a -> b) -> a -> b
$ \s
_ -> m (a, s)
m'), s
s')
          )
        )
        (StateT s m a -> s -> m (a, s)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
LSt.runStateT StateT s m a
m s
s)
  {-# INLINE threadEff #-}

instance ThreadsEff (SSt.StateT s) Split where
  threadEff :: (forall x. Split m x -> m x)
-> Split (StateT s m) a -> StateT s m a
threadEff forall x. Split m x -> m x
alg (Split Maybe (a, StateT s m a) -> a
c StateT s m a
m) = (s -> m (a, s)) -> StateT s m a
forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
SSt.StateT ((s -> m (a, s)) -> StateT s m a)
-> (s -> m (a, s)) -> StateT s m a
forall a b. (a -> b) -> a -> b
$ \s
s ->
    Split m (a, s) -> m (a, s)
forall x. Split m x -> m x
alg (Split m (a, s) -> m (a, s)) -> Split m (a, s) -> m (a, s)
forall a b. (a -> b) -> a -> b
$
      (Maybe ((a, s), m (a, s)) -> (a, s)) -> m (a, s) -> Split m (a, s)
forall a (m :: * -> *) b. (Maybe (a, m a) -> b) -> m a -> Split m b
Split
        ((a, s)
-> (((a, s), m (a, s)) -> (a, s))
-> Maybe ((a, s), m (a, s))
-> (a, s)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
          (Maybe (a, StateT s m a) -> a
c Maybe (a, StateT s m a)
forall a. Maybe a
Nothing, s
s)
          (\((a
a, s
s'), m (a, s)
m') ->
             (Maybe (a, StateT s m a) -> a
c (Maybe (a, StateT s m a) -> a) -> Maybe (a, StateT s m a) -> a
forall a b. (a -> b) -> a -> b
$ (a, StateT s m a) -> Maybe (a, StateT s m a)
forall a. a -> Maybe a
Just (a
a, (s -> m (a, s)) -> StateT s m a
forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
SSt.StateT ((s -> m (a, s)) -> StateT s m a)
-> (s -> m (a, s)) -> StateT s m a
forall a b. (a -> b) -> a -> b
$ \s
_ -> m (a, s)
m'), s
s')
          )
        )
        (StateT s m a -> s -> m (a, s)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
SSt.runStateT StateT s m a
m s
s)
  {-# INLINE threadEff #-}

instance Monoid s => ThreadsEff (LWr.WriterT s) Split where
  threadEff :: (forall x. Split m x -> m x)
-> Split (WriterT s m) a -> WriterT s m a
threadEff forall x. Split m x -> m x
alg (Split Maybe (a, WriterT s m a) -> a
c WriterT s m a
m) = m (a, s) -> WriterT s m a
forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
LWr.WriterT (m (a, s) -> WriterT s m a) -> m (a, s) -> WriterT s m a
forall a b. (a -> b) -> a -> b
$
    Split m (a, s) -> m (a, s)
forall x. Split m x -> m x
alg (Split m (a, s) -> m (a, s)) -> Split m (a, s) -> m (a, s)
forall a b. (a -> b) -> a -> b
$
      (Maybe ((a, s), m (a, s)) -> (a, s)) -> m (a, s) -> Split m (a, s)
forall a (m :: * -> *) b. (Maybe (a, m a) -> b) -> m a -> Split m b
Split
        ((a, s)
-> (((a, s), m (a, s)) -> (a, s))
-> Maybe ((a, s), m (a, s))
-> (a, s)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
          (Maybe (a, WriterT s m a) -> a
c Maybe (a, WriterT s m a)
forall a. Maybe a
Nothing, s
forall a. Monoid a => a
mempty)
          (\ ~( ~(a
a, s
s'), m (a, s)
m') ->
             (Maybe (a, WriterT s m a) -> a
c (Maybe (a, WriterT s m a) -> a) -> Maybe (a, WriterT s m a) -> a
forall a b. (a -> b) -> a -> b
$ (a, WriterT s m a) -> Maybe (a, WriterT s m a)
forall a. a -> Maybe a
Just (a
a, m (a, s) -> WriterT s m a
forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
LWr.WriterT m (a, s)
m'), s
s')
          )
        )
        (WriterT s m a -> m (a, s)
forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
LWr.runWriterT WriterT s m a
m)
  {-# INLINE threadEff #-}

instance Monoid s => ThreadsEff (SWr.WriterT s) Split where
  threadEff :: (forall x. Split m x -> m x)
-> Split (WriterT s m) a -> WriterT s m a
threadEff forall x. Split m x -> m x
alg (Split Maybe (a, WriterT s m a) -> a
c WriterT s m a
m) = m (a, s) -> WriterT s m a
forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
SWr.WriterT (m (a, s) -> WriterT s m a) -> m (a, s) -> WriterT s m a
forall a b. (a -> b) -> a -> b
$
    Split m (a, s) -> m (a, s)
forall x. Split m x -> m x
alg (Split m (a, s) -> m (a, s)) -> Split m (a, s) -> m (a, s)
forall a b. (a -> b) -> a -> b
$
      (Maybe ((a, s), m (a, s)) -> (a, s)) -> m (a, s) -> Split m (a, s)
forall a (m :: * -> *) b. (Maybe (a, m a) -> b) -> m a -> Split m b
Split
        ((a, s)
-> (((a, s), m (a, s)) -> (a, s))
-> Maybe ((a, s), m (a, s))
-> (a, s)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
          (Maybe (a, WriterT s m a) -> a
c Maybe (a, WriterT s m a)
forall a. Maybe a
Nothing, s
forall a. Monoid a => a
mempty)
          (\((a
a, s
s'), m (a, s)
m') ->
             (Maybe (a, WriterT s m a) -> a
c (Maybe (a, WriterT s m a) -> a) -> Maybe (a, WriterT s m a) -> a
forall a b. (a -> b) -> a -> b
$ (a, WriterT s m a) -> Maybe (a, WriterT s m a)
forall a. a -> Maybe a
Just (a
a, m (a, s) -> WriterT s m a
forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
SWr.WriterT m (a, s)
m'), s
s')
          )
        )
        (WriterT s m a -> m (a, s)
forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
SWr.runWriterT WriterT s m a
m)
  {-# INLINE threadEff #-}

instance Monoid s => ThreadsEff (CPSWr.WriterT s) Split where
  threadEff :: (forall x. Split m x -> m x)
-> Split (WriterT s m) a -> WriterT s m a
threadEff forall x. Split m x -> m x
alg (Split Maybe (a, WriterT s m a) -> a
c WriterT s m a
m) = m (a, s) -> WriterT s m a
forall (m :: * -> *) w a.
(Functor m, Monoid w) =>
m (a, w) -> WriterT w m a
CPSWr.writerT (m (a, s) -> WriterT s m a) -> m (a, s) -> WriterT s m a
forall a b. (a -> b) -> a -> b
$
    Split m (a, s) -> m (a, s)
forall x. Split m x -> m x
alg (Split m (a, s) -> m (a, s)) -> Split m (a, s) -> m (a, s)
forall a b. (a -> b) -> a -> b
$
      (Maybe ((a, s), m (a, s)) -> (a, s)) -> m (a, s) -> Split m (a, s)
forall a (m :: * -> *) b. (Maybe (a, m a) -> b) -> m a -> Split m b
Split
        ((a, s)
-> (((a, s), m (a, s)) -> (a, s))
-> Maybe ((a, s), m (a, s))
-> (a, s)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
          (Maybe (a, WriterT s m a) -> a
c Maybe (a, WriterT s m a)
forall a. Maybe a
Nothing, s
forall a. Monoid a => a
mempty)
          (\((a
a, s
s'), m (a, s)
m') ->
             (Maybe (a, WriterT s m a) -> a
c (Maybe (a, WriterT s m a) -> a) -> Maybe (a, WriterT s m a) -> a
forall a b. (a -> b) -> a -> b
$ (a, WriterT s m a) -> Maybe (a, WriterT s m a)
forall a. a -> Maybe a
Just (a
a, m (a, s) -> WriterT s m a
forall (m :: * -> *) w a.
(Functor m, Monoid w) =>
m (a, w) -> WriterT w m a
CPSWr.writerT m (a, s)
m'), s
s')
          )
        )
        (WriterT s m a -> m (a, s)
forall w (m :: * -> *) a. Monoid w => WriterT w m a -> m (a, w)
CPSWr.runWriterT WriterT s m a
m)
  {-# INLINE threadEff #-}