in-other-words-0.2.0.0: src/Control/Effect/Internal/Select.hs
{-# LANGUAGE DerivingVia #-}
{-# OPTIONS_HADDOCK not-home #-}
module Control.Effect.Internal.Select where
import Control.Effect
import Control.Effect.Cont
-- For coercion purposes
import Control.Effect.Carrier
import Control.Effect.Carrier.Internal.Compose
import Control.Effect.Internal.Cont
import Control.Monad.Trans.Free.Church.Alternate
-- | An effect for backtracking search.
newtype Select s m a where
Select :: (forall r. (a -> m (s, r)) -> m r) -> Select s m a
-- | Perform a search: capture the continuation
-- of the program, so that you may test values of @a@ and observe
-- what corresponding @s@ each value would result in
-- at the end of the program (which may be seen as the evaluation of @a@).
-- When you find a satisfactory @a@, you may return the associated @r@.
--
-- The way higher-order actions interact with the continuation depends
-- on the interpretation of 'Select'. In general, you cannot expect to interact
-- with the continuation in any meaningful way: for example, you should not
-- assume that you will be able to catch an exception thrown at some point in
-- the future of the computation by using 'Control.Effect.Error.catch' on the
-- continuation.
select :: Eff (Select s) m
=> (forall r. (a -> m (s, r)) -> m r) -> m a
select main = send (Select main)
{-# INLINE select #-}
data SelectH r
instance Eff (Shift (s, r)) m
=> Handler (SelectH r) (Select s) m where
effHandler = \case
Select main -> shift @(s, r) $ \c ->
main $ \a -> (\(s,r) -> (s, (s, r))) <$> c a
{-# INLINEABLE effHandler #-}
newtype SelectC s r m a = SelectC {
unSelectC ::
ReinterpretC (SelectH r) (Select s) '[Shift (s, r)]
( ShiftC (s, r)
( m
)) a
} deriving ( Functor, Applicative, Monad
, MonadFail, MonadIO
, MonadThrow, MonadCatch
, MonadBase b
)
deriving MonadTrans
via CompositionBaseT
'[ ReinterpretC (SelectH r) (Select s) '[Shift (s, r)]
, ShiftC (s, r)
]
deriving instance (Carrier m, Threads (FreeT (ContBase (m (s, r)) (s, r))) (Prims m))
=> Carrier (SelectC s r m)
-- | Run a @'Select' s@ effect by providing an evaluator
-- for the final result of type @a@.
--
-- @'Derivs' ('SelectC' s r m) = 'Select' s ': 'Derivs' m@
--
-- @'Control.Effect.Primitive.Prims' ('SelectC' s r m) = 'Control.Effect.Primitive.Prims' m@
runSelect :: forall s a m p
. (Carrier m, Threaders '[ContThreads] m p)
=> (a -> m s)
-> SelectC s a m a
-> m a
runSelect c m =
fmap snd
$ runShift
$ (>>= \a -> (\s -> (s, a)) <$> lift (c a))
$ reinterpretViaHandler
$ unSelectC
$ m
{-# INLINE runSelect #-}