{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE TemplateHaskell #-}
module Polysemy.NonDet
(
NonDet (..)
, runNonDet
, runNonDetMaybe
, nonDetToError
) where
import Control.Applicative
import Control.Monad.Trans.Maybe
import Polysemy
import Polysemy.Error
import Polysemy.Internal
import Polysemy.Internal.NonDet
import Polysemy.Internal.Union
runNonDet :: Alternative f => Sem (NonDet ': r) a -> Sem r (f a)
runNonDet = runNonDetC . runNonDetInC
{-# INLINE runNonDet #-}
runNonDetMaybe :: Sem (NonDet ': r) a -> Sem r (Maybe a)
runNonDetMaybe (Sem sem) = Sem $ \k -> runMaybeT $ sem $ \u ->
case decomp u of
Right (Weaving e s wv ex _) ->
case e of
Empty -> empty
Choose left right ->
MaybeT $ usingSem k $ runMaybeT $ fmap ex $ do
MaybeT (runNonDetMaybe (wv (left <$ s)))
<|> MaybeT (runNonDetMaybe (wv (right <$ s)))
Left x -> MaybeT $
k $ weave (Just ())
(maybe (pure Nothing) runNonDetMaybe)
id
x
{-# INLINE runNonDetMaybe #-}
nonDetToError :: Member (Error e) r
=> e
-> Sem (NonDet ': r) a
-> Sem r a
nonDetToError (e :: e) = interpretH $ \case
Empty -> throw e
Choose left right -> do
left' <- nonDetToError e <$> runT left
right' <- nonDetToError e <$> runT right
raise (left' `catch` \(_ :: e) -> right')
{-# INLINE nonDetToError #-}
runNonDetC :: (Alternative f, Applicative m) => NonDetC m a -> m (f a)
runNonDetC (NonDetC m) = m (fmap . (<|>) . pure) (pure empty)
{-# INLINE runNonDetC #-}
newtype NonDetC m a = NonDetC
{
unNonDetC :: forall b . (a -> m b -> m b) -> m b -> m b
}
deriving (Functor)
instance Applicative (NonDetC m) where
pure a = NonDetC (\ cons -> cons a)
{-# INLINE pure #-}
NonDetC f <*> NonDetC a = NonDetC $ \ cons ->
f (\ f' -> a (cons . f'))
{-# INLINE (<*>) #-}
instance Alternative (NonDetC m) where
empty = NonDetC (\ _ nil -> nil)
{-# INLINE empty #-}
NonDetC l <|> NonDetC r = NonDetC $ \ cons -> l cons . r cons
{-# INLINE (<|>) #-}
instance Monad (NonDetC m) where
NonDetC a >>= f = NonDetC $ \ cons ->
a (\ a' -> unNonDetC (f a') cons)
{-# INLINE (>>=) #-}
runNonDetInC :: Sem (NonDet ': r) a -> NonDetC (Sem r) a
runNonDetInC = usingSem $ \u ->
case decomp u of
Left x -> consC $ fmap getNonDetState $
liftSem $ weave (NonDetState (Just ((), empty)))
distribNonDetC
(fmap fst . getNonDetState)
x
Right (Weaving Empty _ _ _ _) -> empty
Right (Weaving (Choose left right) s wv ex _) -> fmap ex $
runNonDetInC (wv (left <$ s)) <|> runNonDetInC (wv (right <$ s))
{-# INLINE runNonDetInC #-}
newtype NonDetState r a = NonDetState {
getNonDetState :: Maybe (a, NonDetC (Sem r) a)
} deriving (Functor)
distribNonDetC :: NonDetState r (Sem (NonDet ': r) a) -> Sem r (NonDetState r a)
distribNonDetC = \case
NonDetState (Just (a, r)) ->
fmap NonDetState $ unconsC $ runNonDetInC a <|> (r >>= runNonDetInC)
_ ->
pure (NonDetState Nothing)
{-# INLINE distribNonDetC #-}
unconsC :: NonDetC (Sem r) a -> Sem r (Maybe (a, NonDetC (Sem r) a))
unconsC (NonDetC n) = n (\a r -> pure (Just (a, consC r))) (pure Nothing)
{-# INLINE unconsC #-}
consC :: Sem r (Maybe (a, NonDetC (Sem r) a)) -> NonDetC (Sem r) a
consC m = NonDetC $ \cons nil -> m >>= \case
Just (a, r) -> cons a (unNonDetC r cons nil)
_ -> nil
{-# INLINE consC #-}