module Control.Effect.Optional ( -- * Effects Optional(..) , HoistOption , HoistOptionCall(..) -- * Actions , optionally , hoistOption -- * Interpretations , runHoistOption , hoistOptionToFinal -- * Threading utilities , threadOptionalViaBaseControl -- * Combinators for 'Algebra's -- Intended to be used for custom 'Carrier' instances when -- defining 'algPrims'. , powerAlgHoistOption , powerAlgHoistOptionFinal -- * Carriers , HoistOptionC , HoistOptionToFinalC ) where import Control.Monad import Control.Monad.Trans.Control import Control.Effect import Control.Effect.Carrier import Control.Effect.Internal.Optional import Control.Effect.Type.Internal.BaseControl import Control.Effect.Type.Optional -- | Execute the provided computation, providing the -- interpretation of @'Optional' s@ the option to execute -- it in full or in part. optionally :: Eff (Optional s) m => s a -> m a -> m a optionally s m = send (Optionally s m) {-# INLINE optionally #-} -- | Hoist a natural transformation of the base monad into the current -- monad, equipped with the option to execute the provided computation -- in full or in part. hoistOption :: Eff (HoistOption b) m => (forall x. (a -> x) -> b x -> b x) -> m a -> m a hoistOption n = optionally (HoistOptionCall n) {-# INLINE hoistOption #-} -- | Runs a @'HoistOption' m@ effect, where the base monad -- @m@ is the current monad. -- -- @'Derivs' ('HoistOptionC' m) = 'HoistOption' m ': 'Derivs' m@ -- -- @'Prims' ('HoistOptionC' m) = 'HoistOption' m ': 'Prims' m@ runHoistOption :: Carrier m => HoistOptionC m a -> m a runHoistOption = unHoistOptionC {-# INLINE runHoistOption #-} data HoistOptionToFinalH instance ( Carrier m , MonadBaseControl b m ) => PrimHandler HoistOptionToFinalH (HoistOption b) m where effPrimHandler (Optionally (HoistOptionCall b) m) = join $ liftBaseWith $ \lower -> b pure (restoreM <$> lower m) {-# INLINEABLE effPrimHandler #-} type HoistOptionToFinalC b = InterpretPrimC HoistOptionToFinalH (HoistOption b) -- | Runs a @'HoistOption' b@ effect, where the base monad -- @b@ is the final base monad. -- -- @'Derivs' ('HoistOptionToFinalC' b m) = 'HoistOption' b ': 'Derivs' m@ -- -- @'Prims' ('HoistOptionToFinalC' b m) = 'HoistOption' b ': 'Prims' m@ hoistOptionToFinal :: ( MonadBaseControl b m , Carrier m ) => HoistOptionToFinalC b m a -> m a hoistOptionToFinal = interpretPrimViaHandler {-# INLINE hoistOptionToFinal #-} -- | Strengthen an @'Algebra' p m@ by adding a @'HoistOption' m@ handler powerAlgHoistOption :: forall m p a . Algebra' p m a -> Algebra' (HoistOption m ': p) m a powerAlgHoistOption alg = powerAlg alg $ \case Optionally (HoistOptionCall b) m -> b id m {-# INLINE powerAlgHoistOption #-} -- | Strengthen an @'Algebra' p m@ by adding a @'HoistOption' b@ handler, where -- @b@ is the final base monad. powerAlgHoistOptionFinal :: forall b m p a . MonadBaseControl b m => Algebra' p m a -> Algebra' (HoistOption b ': p) m a powerAlgHoistOptionFinal alg = powerAlg alg $ \case Optionally (HoistOptionCall b) m -> join $ liftBaseWith $ \lower -> b pure (restoreM <$> lower m) {-# INLINE powerAlgHoistOptionFinal #-}