Strafunski-StrategyLib-5.0.0.1: Data/Generics/Strafunski/StrategyLib/EffectTheme.hs
------------------------------------------------------------------------------
-- |
-- Maintainer : Ralf Laemmel, Joost Visser
-- Stability : experimental
-- Portability : portable
--
-- This module is part of 'StrategyLib', a library of functional strategy
-- combinators, including combinators for generic traversal. This module
-- provides combinators to localize monadic effects.
--
------------------------------------------------------------------------------
module Data.Generics.Strafunski.StrategyLib.EffectTheme (
-- * Replace one strategy monad by another
mrunTP, mrunTU,
-- * Add an effect to the strategy monad
liftTP, liftTU,
-- * Remove an effect from the strategy monad
unliftTP, unliftTU,
-- * Localize specific effects
-- ** Localize the partiality effect
guaranteeSuccessTP, guaranteeSuccessTU,
unsafeGuaranteeSuccessTP,
-- ** Localize the state effect
localStateTP, localStateTU,
) where
import Control.Monad.Run
import Control.Monad.Trans
import Data.Generics.Strafunski.StrategyLib.StrategyPrelude
import Data.Generics.Strafunski.StrategyLib.OverloadingTheme
import Data.Generics.Strafunski.StrategyLib.Models.Deriving.StrategyPrimitives
------------------------------------------------------------------------------
-- * Replace one strategy monad by another
-- The two monads are unrelated.
-- The first is run, and the resulting value is returned in the other.
-- We use the `run' function of one monad, and the `return' function
-- of the other.
-- | Replace the monad in a type-preserving strategy, given a monad
-- algebra (see 'MonadRun') for the monad that is replaced. The two
-- monads are unrelated, so none of the effects in the monad that is
-- replaced carry over to the one that replaces it.
mrunTP :: (Monad m, Monad m', MonadRun s m)
=> (forall a . s a a) -> TP m -> TP m'
mrunTP alg = msubstTP (mrun alg)
-- | Replace the monad in a type-unifying strategy, given a monad
-- algebra (see 'MonadRun') for the monad that is replaced. The two
-- monads are unrelated, so none of the effects in the monad that is
-- replaced carry over to the one that replaces it.
mrunTU :: (Monad m, Monad m', MonadRun s m)
=> s a a -> TU a m -> TU a m'
mrunTU alg = msubstTU (mrun alg)
------------------------------------------------------------------------------
-- * Add an effect to the strategy monad
-- | Add an effect to the monad in a type-preserving strategy.
-- The monads are related by a monad transformer, so the effects of the
-- incoming monad are preserved in the result monad. We use the `lift'
-- function of the monad transformer.
liftTP :: (Monad (t m), Monad m, MonadTrans t) => TP m -> TP (t m)
liftTP = msubstTP lift
-- | Add an effect to the monad in a type-unifying strategy.
-- The monads are related by a monad transformer, so the effects of the
-- incoming monad are preserved in the result monad. We use the `lift'
-- function of the monad transformer.
liftTU :: (Monad (t m), Monad m, MonadTrans t) => TU a m -> TU a (t m)
liftTU = msubstTU lift
------------------------------------------------------------------------------
-- * Remove an effect from the strategy monad
-- | remove an effect from the monad of a type-preserving strategy.
-- The monads are related by a monad untransformer (see 'MonadUnTrans'),
-- so the effects of the incoming monad are preserved in the result
-- monad, except for the effect for which a monad algebra is supplied.
unliftTP :: (Monad (t m), Monad m, MonadUnTrans s t)
=> (forall a . s a a) -> TP (t m) -> TP m
unliftTP alg = msubstTP (unlift alg)
-- | remove an effect from the monad of a type-unifying strategy.
-- The monads are related by a monad untransformer (see 'MonadUnTrans'),
-- so the effects of the incoming monad are preserved in the result
-- monad, except for the effect for which a monad algebra is supplied.
unliftTU :: (Monad (t m), Monad m, MonadUnTrans s t)
=> s a a -> TU a (t m) -> TU a m
unliftTU alg = msubstTU (unlift alg)
-- Does not work:
-- unliftS alg = msubstS (unlift alg)
------------------------------------------------------------------------------
-- * Localize specific effects
-- ** Localize the partiality effect
-- Safe versions provide default to cope with Nothing.
-- Note the explicit universal quantification of this value
-- in the TP case.
-- | Localize the partiality effect in a type-preserving strategy. A
-- default value must be supplied to be used to recover from
-- failure. Since this default parameter is universally quantified,
-- only 'undefined' and 'error ...' can be used to instantiate it.
-- See also 'unsafeGuaranteeSuccessTP.
guaranteeSuccessTP :: (Monad (t m), Monad m, MonadUnTrans MaybeAlg t)
=> (forall a . a) -- ^ default value (Note: universally quantified!)
-> TP (t m) -- ^ type-preserving partial strategy
-> TP m -- ^ type-preserving strategy without partiality
guaranteeSuccessTP x s
= unliftTP (MaybeAlg x id) s
-- | Localize the partiality effect in a type-unifying strategy. A
-- default value must be supplied to be used to recover from
-- failure.
guaranteeSuccessTU :: (Monad (t m), Monad m, MonadUnTrans MaybeAlg t)
=> a -- ^ default value
-> TU a (t m) -- ^ type-preserving partial strategy
-> TU a m -- ^ type-preserving strategy without partiality
guaranteeSuccessTU x s
= unliftTU (MaybeAlg x id) s
-- Does not work:
-- guaranteeSuccessS :: (Monad (t m), Monad m, MonadUnTrans MaybeAlg t)
-- => a -> TU a (t m) -> TU a m
-- guaranteeSuccessS x s
-- = msubstS (unlift (MaybeAlg x id)) s
-- | Unsafe version of 'guaranteeSuccessTP'. This version uses uses `undefined'
-- to recover from failure. For the type-preserving case, this is the only
-- possible default value.
unsafeGuaranteeSuccessTP :: (Monad (t m), Monad m, MonadUnTrans MaybeAlg t)
=> TP (t m) -> TP m
unsafeGuaranteeSuccessTP s
= guaranteeSuccessTP undefined s
-- | Unsafe version of 'guaranteeSuccessTU'. This version uses uses `undefined'
-- to recover from failure. Use 'guaranteeSuccessTU' instead.
unsafeGuaranteeSuccessTU :: (Monad (t m), Monad m, MonadUnTrans MaybeAlg t)
=> TU a (t m) -> TU a m
unsafeGuaranteeSuccessTU s
= guaranteeSuccessTU undefined s
-- Does not work:
-- unsafeGuaranteeSuccessS s
-- = guaranteeSuccessS undefined s
------------------------------------------------------------------------------
-- ** Localize the state effect
-- | Localize the state of a type-preserving strategy. The first argument
-- represents the initial state.
localStateTP :: (Monad (t m), Monad m, MonadUnTrans (StateAlg s) t)
=> s -> TP (t m) -> TP m
localStateTP s
= unliftTP (StateAlg s fst)
-- | Localize the state of a type-unifying strategy. The first argument
-- represents the initial state.
localStateTU :: (Monad (t m), Monad m, MonadUnTrans (StateAlg s) t)
=> s -> TU a (t m) -> TU a m
localStateTU s
= unliftTU (StateAlg s fst)
------------------------------------------------------------------------------