{-# OPTIONS_HADDOCK not-home #-}
module Control.Effect.Internal.NonDet where
import Data.Coerce
import Control.Effect
import Control.Effect.Carrier
import Control.Effect.Type.Split
import Control.Effect.Type.Regional
import Control.Effect.Internal.Utils
import qualified Control.Monad.Trans.List.Church as L
newtype NonDet m a where
FromList :: [a] -> NonDet m a
newtype Cull m a where
Cull :: m a -> Cull m a
data Cut m a where
Cutfail :: Cut m a
Call :: m a -> Cut m a
type Logic = Bundle '[NonDet, Cull, Cut, Split]
type NonDetThreads = Threads L.ListT
newtype LogicC m a = LogicC { unLogicC :: L.ListT m a }
deriving ( Functor, Applicative, Monad
, MonadFail, MonadIO, MonadBase b
, MonadThrow, MonadCatch
)
deriving MonadTrans
instance ( Carrier m
, Threads L.ListT (Prims m)
) => Carrier (LogicC m) where
type Derivs (LogicC m) = Split ': Cull ': Cut ': NonDet ': Derivs m
type Prims (LogicC m) = Split ': Regional CullOrCall ': Prims m
algPrims = powerAlg (coerce (algPrims @(CullCutC m))) $ \case
Split cn (m :: LogicC m a) -> fmap cn (coerce (L.split @m @a) m)
{-# INLINE algPrims #-}
reformulate = addPrim $ coerceReform $ reformulate @(CullCutC m)
{-# INLINE reformulate #-}
data CullOrCall
= DoCull
| DoCall
newtype CullCutC m a = CullCutC { unCullCutC :: L.ListT m a }
deriving ( Functor, Applicative, Monad
, MonadFail, MonadIO, MonadBase b
, MonadThrow, MonadCatch
)
deriving MonadTrans
instance ( Carrier m
, Threads L.ListT (Prims m)
) => Carrier (CullCutC m) where
type Derivs (CullCutC m) = Cull ': Cut ': NonDet ': Derivs m
type Prims (CullCutC m) = Regional CullOrCall ': Prims m
algPrims =
powerAlg (
coerce (algPrims @(NonDetC m))
) $ \case
Regionally DoCull m -> coerceTrans (L.cull @m) m
Regionally DoCall m -> coerceTrans (L.call @m) m
{-# INLINEABLE algPrims #-}
reformulate n alg =
powerAlg (
powerAlg (
coerceReform (reformulate @(NonDetC m)) n (weakenAlg alg)
) $ \case
Cutfail -> n (CullCutC L.cutfail)
Call m -> (alg . inj) $ Regionally DoCall m
) $ \case
Cull m -> (alg . inj) $ Regionally DoCull m
{-# INLINEABLE reformulate #-}
newtype NonDetC m a = NonDetC { unNonDetC :: L.ListT m a }
deriving ( Functor, Applicative, Monad
, MonadFail, MonadIO, MonadBase b
, MonadThrow, MonadCatch
)
deriving MonadTrans
instance ( Carrier m
, Threads L.ListT (Prims m)
) => Carrier (NonDetC m) where
type Derivs (NonDetC m) = NonDet ': Derivs m
type Prims (NonDetC m) = Prims m
algPrims = coerce (thread @L.ListT (algPrims @m))
{-# INLINEABLE algPrims #-}
reformulate n alg =
powerAlg
(liftReform reformulate n alg)
$ \case
FromList l -> n $ NonDetC $ L.ListT $ \_ c b _ -> foldr c b l
{-# INLINEABLE reformulate #-}
runNonDet :: forall f m a p
. ( Alternative f
, Carrier m
, Threaders '[NonDetThreads] m p
)
=> NonDetC m a
-> m (f a)
runNonDet = L.runListT .# unNonDetC
{-# INLINE runNonDet #-}
runNonDet1 :: forall m a p
. ( Carrier m
, Threaders '[NonDetThreads] m p
)
=> NonDetC m a
-> m (Maybe a)
runNonDet1 m =
L.unListT (unNonDetC m)
(>>=)
(\a _ -> pure (Just a))
(pure Nothing)
(pure Nothing)
{-# INLINE runNonDet1 #-}
runCullCut :: forall f m a p
. ( Alternative f
, Carrier m
, Threaders '[NonDetThreads] m p
)
=> CullCutC m a
-> m (f a)
runCullCut = L.runListT .# unCullCutC
runLogic :: forall f m a p
. ( Alternative f
, Carrier m
, Threaders '[NonDetThreads] m p
)
=> LogicC m a
-> m (f a)
runLogic = L.runListT .# unLogicC