{-# LANGUAGE DeriveFunctor, FlexibleInstances, LambdaCase, MultiParamTypeClasses, TypeOperators, UndecidableInstances #-}
module Control.Effect.NonDet
( NonDet(..)
, Alternative(..)
, runNonDet
, AltC(..)
, runNonDetOnce
, OnceC(..)
, Branch(..)
, branch
, runBranch
) where
import Control.Applicative (Alternative(..), liftA2)
import Control.Effect.Carrier
import Control.Effect.Cull
import Control.Effect.Internal
import Control.Effect.NonDet.Internal
import Control.Effect.Sum
runNonDet :: (Alternative f, Monad f, Traversable f, Carrier sig m, Effect sig, Applicative m) => Eff (AltC f m) a -> m (f a)
runNonDet = runAltC . interpret
newtype AltC f m a = AltC { runAltC :: m (f a) }
instance (Alternative f, Monad f, Traversable f, Carrier sig m, Effect sig, Applicative m) => Carrier (NonDet :+: sig) (AltC f m) where
ret a = AltC (ret (pure a))
eff = AltC . handleSum (eff . handleTraversable runAltC) (\case
Empty -> ret empty
Choose k -> liftA2 (<|>) (runAltC (k True)) (runAltC (k False)))
runNonDetOnce :: (Alternative f, Monad f, Traversable f, Carrier sig m, Effect sig, Monad m) => Eff (OnceC f m) a -> m (f a)
runNonDetOnce = runNonDet . runCull . cull . runOnceC . interpret
newtype OnceC f m a = OnceC { runOnceC :: Eff (CullC (Eff (AltC f m))) a }
instance (Alternative f, Carrier sig m, Effect sig, Traversable f, Monad f, Monad m) => Carrier (NonDet :+: sig) (OnceC f m) where
ret = OnceC . ret
eff = OnceC . handleSum (eff . R . R . R . handleCoercible) (\case
Empty -> empty
Choose k -> runOnceC (k True) <|> runOnceC (k False))