{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, StandaloneDeriving, TypeOperators, UndecidableInstances #-}
module Control.Carrier.Cull.Church
(
runCull
, runCullA
, runCullM
, CullC(..)
, module Control.Effect.Cull
, module Control.Effect.NonDet
) where
import Control.Algebra
import Control.Applicative (liftA2)
import Control.Carrier.NonDet.Church
import Control.Carrier.Reader
import Control.Effect.Cull
import Control.Effect.NonDet
import qualified Control.Monad.Fail as Fail
import Control.Monad.Fix
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
runCull :: (m b -> m b -> m b) -> (a -> m b) -> m b -> CullC m a -> m b
runCull fork leaf nil (CullC m) = runNonDet fork leaf nil (runReader False m)
runCullA :: (Alternative f, Applicative m) => CullC m a -> m (f a)
runCullA = runCull (liftA2 (<|>)) (pure . pure) (pure empty)
runCullM :: (Applicative m, Monoid b) => (a -> b) -> CullC m a -> m b
runCullM leaf = runCull (liftA2 mappend) (pure . leaf) (pure mempty)
newtype CullC m a = CullC (ReaderC Bool (NonDetC m) a)
deriving (Applicative, Functor, Monad, Fail.MonadFail, MonadIO)
instance Alternative (CullC m) where
empty = CullC empty
{-# INLINE empty #-}
CullC l <|> CullC r = CullC $ ReaderC $ \ cull ->
if cull then
NonDetC $ \ fork leaf nil ->
runNonDet fork leaf (runNonDet fork leaf nil (runReader cull r)) (runReader cull l)
else
runReader cull l <|> runReader cull r
{-# INLINE (<|>) #-}
deriving instance MonadFix m => MonadFix (CullC m)
instance MonadPlus (CullC m)
instance MonadTrans CullC where
lift = CullC . lift . lift
{-# INLINE lift #-}
instance (Algebra sig m, Effect sig) => Algebra (Cull :+: NonDet :+: sig) (CullC m) where
alg (L (Cull (CullC m) k)) = CullC (local (const True) m) >>= k
alg (R (L (L Empty))) = empty
alg (R (L (R (Choose k)))) = k True <|> k False
alg (R (R other)) = CullC (alg (R (R (handleCoercible other))))
{-# INLINE alg #-}