{-# LANGUAGE AllowAmbiguousTypes, TemplateHaskell #-} -- | Description: Interpreters for 'Fixpoint' module Polysemy.Fixpoint ( -- * Effect Fixpoint (..) -- * Interpretations , module Polysemy.Fixpoint ) where import Control.Monad.Fix import Data.Maybe import Polysemy import Polysemy.Final import Polysemy.Internal.Fixpoint ----------------------------------------------------------------------------- -- | Run a 'Fixpoint' effect in terms of a final 'MonadFix' instance. -- -- If you need to run a 'Fixpoint' effect purely, use this together with -- @'Final' 'Data.Functor.Identity.Identity'@. -- -- __Note__: This is subject to the same traps as 'MonadFix' instances for -- monads with failure: this will throw an exception if you try to recursively use -- the result of a failed computation in an action whose effect may be observed -- even though the computation failed. -- -- For example, the following program will throw an exception upon evaluating the -- final state: -- -- @ -- bad :: (Int, Either () Int) -- bad = -- 'Data.Functor.Identity.runIdentity' -- . 'runFinal' -- . 'fixpointToFinal' \@'Data.Functor.Identity.Identity' -- . 'Polysemy.State.runLazyState' \@Int 1 -- . 'Polysemy.Error.runError' -- $ mdo -- 'Polysemy.State.put' a -- a <- 'Polysemy.Error.throw' () -- return a -- @ -- -- 'fixpointToFinal' also operates under the assumption that any effectful -- state which can't be inspected using 'Polysemy.Inspector' can't contain any -- values. For example, the effectful state for 'Polysemy.Error.runError' is -- @'Either' e a@. The inspector for this effectful state only fails if the -- effectful state is a @'Left'@ value, which therefore doesn't contain any -- values of @a@. -- -- This assumption holds true for all interpreters featured in this package, -- and is presumably always true for any properly implemented interpreter. -- 'fixpointToFinal' may throw an exception if it is used together with an -- interpreter that uses 'Polysemy.Internal.Union.weave' improperly. -- -- If 'fixpointToFinal' throws an exception for you, and it can't -- be due to any of the above, then open an issue over at the -- GitHub repository for polysemy. -- -- @since 1.2.0.0 fixpointToFinal :: forall m r a . (Member (Final m) r, MonadFix m) => Sem (Fixpoint ': r) a -> Sem r a fixpointToFinal = interpretFinal @m $ \(Fixpoint f) -> do f' <- bindS f s <- getInitialStateS ins <- getInspectorS pure $ mfix $ \fa -> f' $ fromMaybe (bomb "fixpointToFinal") (inspect ins fa) <$ s {-# INLINE fixpointToFinal #-}