packages feed

polysemy-zoo 0.5.0.1 → 0.6.0.0

raw patch · 28 files changed

+1091/−645 lines, 28 filesdep +contravariantdep +transformersdep ~polysemydep ~polysemy-pluginPVP ok

version bump matches the API change (PVP)

Dependencies added: contravariant, transformers

Dependency ranges changed: polysemy, polysemy-plugin

API changes (from Hackage documentation)

- Polysemy.Cont: runContFinal :: (Member (Final m) r, MonadCont m) => Sem (Cont (ExitRef m) : r) a -> Sem r a
- Polysemy.Final: [WithWeaving] :: (forall f. Functor f => f () -> (forall x. f (z x) -> m (f x)) -> (forall x. f x -> Maybe x) -> m (f a)) -> Final m z a
- Polysemy.Final: bindS :: Monad m => (a -> n b) -> Sem (WithStrategy m f n) (f a -> m (f b))
- Polysemy.Final: data Final m z a
- Polysemy.Final: embedFinal :: Functor m => Member (Final m) r => m a -> Sem r a
- Polysemy.Final: getInitialStateS :: Sem (WithStrategy m f n) (f ())
- Polysemy.Final: getInspectorS :: Sem (WithStrategy m f n) (Inspector f)
- Polysemy.Final: interpretFinal :: forall e m r a. (Member (Final m) r, Functor m) => (forall x n. e n x -> Strategic m n x) -> Sem (e : r) a -> Sem r a
- Polysemy.Final: liftS :: Functor m => m a -> Strategic m n a
- Polysemy.Final: pureS :: Applicative m => a -> Strategic m n a
- Polysemy.Final: runFinal :: Monad m => Sem '[Final m, Embed m] a -> m a
- Polysemy.Final: runFinalLift :: Monad m => (forall x. n x -> m x) -> Sem [Final m, Embed m, Embed n] a -> m a
- Polysemy.Final: runFinalLiftIO :: MonadIO m => Sem [Final m, Embed m, Embed IO] a -> m a
- Polysemy.Final: runS :: Monad m => n a -> Sem (WithStrategy m f n) (m (f a))
- Polysemy.Final: type Strategic m n a = forall f. Functor f => Sem (WithStrategy m f n) (m (f a))
- Polysemy.Final: type WithStrategy m f n = WithTactics (Embed m) f n '[]
- Polysemy.Final: withStrategic :: Member (Final m) r => Strategic m (Sem r) a -> Sem r a
- Polysemy.Final: withWeaving :: forall m a r. Member (Final m) r => (forall f. Functor f => f () -> (forall x. f (Sem r x) -> m (f x)) -> (forall x. f x -> Maybe x) -> m (f a)) -> Sem r a
- Polysemy.Final.Async: runAsyncFinal :: Member (Final IO) r => Sem (Async : r) a -> Sem r a
- Polysemy.Final.Error: instance Data.Typeable.Internal.Typeable e => GHC.Exception.Type.Exception (Polysemy.Final.Error.WrappedExc e)
- Polysemy.Final.Error: instance Data.Typeable.Internal.Typeable e => GHC.Show.Show (Polysemy.Final.Error.WrappedExc e)
- Polysemy.Final.Error: runErrorInIOFinal :: (Typeable e, Member (Final IO) r) => Sem (Error e : r) a -> Sem r (Either e a)
- Polysemy.Final.Fixpoint: runFixpointFinal :: (Member (Final m) r, MonadFix m) => Sem (Fixpoint : r) a -> Sem r a
- Polysemy.Final.MTL: runErrorFinal :: (Member (Final m) r, MonadError e m) => Sem (Error e : r) a -> Sem r a
- Polysemy.Final.MTL: runReaderFinal :: (Member (Final m) r, MonadReader i m) => Sem (Reader i : r) a -> Sem r a
- Polysemy.Final.MTL: runStateFinal :: (Member (Embed m) r, MonadState s m) => Sem (State s : r) a -> Sem r a
- Polysemy.Final.MTL: runWriterFinal :: (Member (Final m) r, MonadWriter o m) => Sem (Writer o : r) a -> Sem r a
- Polysemy.Final.Resource: runResourceFinal :: Member (Final IO) r => Sem (Resource : r) a -> Sem r a
- Polysemy.Shift: runShiftFinal :: forall s m a r. (Member (Final (ContT (Maybe s) m)) r, Monad m) => Sem (Shift (Ref m (Maybe s)) s : r) a -> Sem r a
+ Polysemy.ConstraintAbsorber.MonadCont: absorbCont :: Member (Cont ref) r => (MonadCont (Sem r) => Sem r a) -> Sem r a
+ Polysemy.ConstraintAbsorber.MonadCont: instance forall (m :: * -> *) k (s' :: k). GHC.Base.Applicative m => GHC.Base.Applicative (Polysemy.ConstraintAbsorber.MonadCont.Action m s')
+ Polysemy.ConstraintAbsorber.MonadCont: instance forall (m :: * -> *) k (s' :: k). GHC.Base.Functor m => GHC.Base.Functor (Polysemy.ConstraintAbsorber.MonadCont.Action m s')
+ Polysemy.ConstraintAbsorber.MonadCont: instance forall (m :: * -> *) k (s' :: k). GHC.Base.Monad m => GHC.Base.Monad (Polysemy.ConstraintAbsorber.MonadCont.Action m s')
+ Polysemy.ConstraintAbsorber.MonadCont: instance forall k (m :: * -> *) (s' :: k). (GHC.Base.Monad m, Data.Reflection.Reifies s' (Polysemy.ConstraintAbsorber.MonadCont.ContDict m)) => Control.Monad.Cont.Class.MonadCont (Polysemy.ConstraintAbsorber.MonadCont.Action m s')
+ Polysemy.Cont: contToFinal :: (Member (Final m) r, MonadCont m) => Sem (Cont (ExitRef m) : r) a -> Sem r a
+ Polysemy.Cont: data ViaFreshRef uniq a
+ Polysemy.Cont: runContViaFresh :: forall uniq r a. (Member (Fresh uniq) r, Eq uniq) => Sem (Cont (ViaFreshRef uniq) : r) a -> Sem r (Maybe a)
+ Polysemy.Cont.Internal: ResAndHandler :: a -> ((uniq, Any) -> Sem (Error (uniq, Any) : r) a) -> ContFreshState uniq r a
+ Polysemy.Cont.Internal: ViaFreshRef :: (a -> (uniq, Any)) -> ViaFreshRef uniq a
+ Polysemy.Cont.Internal: [getBacktrackException] :: ViaFreshRef uniq a -> a -> (uniq, Any)
+ Polysemy.Cont.Internal: [getHandler] :: ContFreshState uniq r a -> (uniq, Any) -> Sem (Error (uniq, Any) : r) a
+ Polysemy.Cont.Internal: [getResult] :: ContFreshState uniq r a -> a
+ Polysemy.Cont.Internal: data ContFreshState uniq r a
+ Polysemy.Cont.Internal: data ViaFreshRef uniq a
+ Polysemy.Cont.Internal: instance Data.Functor.Contravariant.Contravariant (Polysemy.Cont.Internal.ViaFreshRef uniq)
+ Polysemy.Cont.Internal: instance GHC.Base.Functor (Polysemy.Cont.Internal.ContFreshState uniq r)
+ Polysemy.Cont.Internal: instance forall k (m :: k -> *) (s :: k). Data.Functor.Contravariant.Contravariant (Polysemy.Cont.Internal.Ref m s)
+ Polysemy.Cont.Internal: instance forall k (m :: k -> *). Data.Functor.Contravariant.Contravariant (Polysemy.Cont.Internal.ExitRef m)
+ Polysemy.Cont.Internal: runContViaFreshInC :: forall uniq s r a. (Member (Fresh uniq) r, Eq uniq) => Sem (Cont (ViaFreshRef uniq) : r) a -> ContT s (Sem (Error (uniq, Any) : r)) a
+ Polysemy.Cont.Internal: runContViaFreshInCWeave :: forall uniq s r a. (Member (Fresh uniq) r, Eq uniq) => Sem (Cont (ViaFreshRef uniq) : r) a -> ContT (ContFreshState uniq r s) (Sem (Error (uniq, Any) : r)) a
+ Polysemy.EndState: [GetEndState] :: EndState s m s
+ Polysemy.EndState: data EndState s m a
+ Polysemy.EndState: getEndState :: forall s_aBgI r_aBhB. MemberWithError (EndState s_aBgI) r_aBhB => Sem r_aBhB s_aBgI
+ Polysemy.EndState: runEndAtomicState :: (Member (AtomicState s) r, Member Fixpoint r) => Sem (EndState s : r) a -> Sem r a
+ Polysemy.EndState: runEndState :: (Member (State s) r, Member Fixpoint r) => Sem (EndState s : r) a -> Sem r a
+ Polysemy.Final.IO: asyncToIOFinalGlobal :: Member (Final IO) r => Sem (Async : r) a -> Sem r a
+ Polysemy.Final.IO: interpretFinalGlobal :: forall e a r. Member (Final IO) r => (forall x n. e n x -> Strategic IO n x) -> Sem (e : r) a -> Sem r a
+ Polysemy.Final.IO: resourceToIOFinalGlobal :: Member (Final IO) r => Sem (Resource : r) a -> Sem r a
+ Polysemy.Final.IO.Internal: bomb :: a
+ Polysemy.Final.IO.Internal: interpretFinalGlobal :: forall e a r. Member (Final IO) r => (forall x n. e n x -> Strategic IO n x) -> Sem (e : r) a -> Sem r a
+ Polysemy.Final.IO.Internal: runViaFinalGlobal :: (Member (Final IO) r, Functor f) => MVar (f ()) -> (forall x. f (Sem r x) -> IO (f x)) -> (forall x. f x -> Maybe x) -> (forall x n. e n x -> Strategic IO n x) -> Sem (e : r) a -> MaybeT IO a
+ Polysemy.Final.MTL: errorToFinal :: (Member (Final m) r, MonadError e m) => Sem (Error e : r) a -> Sem r a
+ Polysemy.Final.MTL: readerToFinal :: (Member (Final m) r, MonadReader i m) => Sem (Reader i : r) a -> Sem r a
+ Polysemy.Final.MTL: stateToEmbed :: (Member (Embed m) r, MonadState s m) => Sem (State s : r) a -> Sem r a
+ Polysemy.Final.MTL: writerToFinal :: (Member (Final m) r, MonadWriter o m) => Sem (Writer o : r) a -> Sem r a
+ Polysemy.Final.More: lowerFinal :: Member (Embed m) r => (forall x. Sem r x -> m x) -> Sem (Final m : r) a -> Sem r a
+ Polysemy.Final.More: runFinalSem :: Sem (Final (Sem r) : r) a -> Sem r a
+ Polysemy.Final.NonDet: nonDetToFinal :: (Member (Final m) r, Alternative m) => Sem (NonDet : r) a -> Sem r a
+ Polysemy.Fresh: [Fresh] :: Fresh uniq m uniq
+ Polysemy.Fresh: data Fresh uniq m a
+ Polysemy.Fresh: fresh :: forall uniq_av8A r_av9t. MemberWithError (Fresh uniq_av8A) r_av9t => Sem r_av9t uniq_av8A
+ Polysemy.Fresh: freshToIO :: Member (Embed IO) r => Sem (Fresh Unique : r) a -> Sem r a
+ Polysemy.Fresh: runFreshEnumUnsafe :: forall n a r. Enum n => Sem (Fresh n : r) a -> Sem r a
+ Polysemy.Fresh: runFreshUnsafePerformIO :: Sem (Fresh Unique : r) a -> Sem r a
+ Polysemy.Reader.More: runReaderFixSem :: forall i r a. Member Fixpoint r => Sem r i -> Sem (Reader i : r) a -> Sem r a
+ Polysemy.RevState: [RevState] :: (s -> (s, a)) -> RevState s m a
+ Polysemy.RevState: instance Control.Monad.Fix.MonadFix m => GHC.Base.Applicative (Polysemy.RevState.LazyRevStateT s m)
+ Polysemy.RevState: instance Control.Monad.Fix.MonadFix m => GHC.Base.Applicative (Polysemy.RevState.RevStateT s m)
+ Polysemy.RevState: instance Control.Monad.Fix.MonadFix m => GHC.Base.Monad (Polysemy.RevState.LazyRevStateT s m)
+ Polysemy.RevState: instance Control.Monad.Fix.MonadFix m => GHC.Base.Monad (Polysemy.RevState.RevStateT s m)
+ Polysemy.RevState: instance GHC.Base.Functor m => GHC.Base.Functor (Polysemy.RevState.LazyRevStateT s m)
+ Polysemy.RevState: instance GHC.Base.Functor m => GHC.Base.Functor (Polysemy.RevState.RevStateT s m)
+ Polysemy.RevState: newtype RevState s m a
+ Polysemy.RevState: revGet :: forall s r. Member (RevState s) r => Sem r s
+ Polysemy.RevState: revModify :: forall s r. Member (RevState s) r => (s -> s) -> Sem r ()
+ Polysemy.RevState: revPut :: forall s r. Member (RevState s) r => Sem r s
+ Polysemy.RevState: revState :: forall s a r. Member (RevState s) r => (s -> (s, a)) -> Sem r a
+ Polysemy.RevState: runLazyRevState :: Member Fixpoint r => s -> Sem (RevState s : r) a -> Sem r (s, a)
+ Polysemy.RevState: runRevState :: Member Fixpoint r => s -> Sem (RevState s : r) a -> Sem r (s, a)
+ Polysemy.Shift: shiftToFinal :: forall s m a r. (Member (Final (ContT (Maybe s) m)) r, Monad m) => Sem (Shift (Ref m (Maybe s)) s : r) a -> Sem r a
+ Polysemy.Tagged: [Tagged] :: forall k e m a. e m a -> Tagged k e m a
+ Polysemy.Tagged: newtype Tagged k e m a
+ Polysemy.Tagged: retag :: forall k1 k2 e r a. Member (Tagged k2 e) r => Sem (Tagged k1 e : r) a -> Sem r a
+ Polysemy.Tagged: tag :: forall k e r a. Member (Tagged k e) r => Sem (e : r) a -> Sem r a
+ Polysemy.Tagged: untag :: forall k e r a. Sem (Tagged k e : r) a -> Sem (e : r) a
- Polysemy.Cont: callCC :: forall ref a r. Member (Cont ref) r => ((forall b. a -> Sem r b) -> Sem r a) -> Sem r a
+ Polysemy.Cont: callCC :: forall ref r a. Member (Cont ref) r => ((forall b. a -> Sem r b) -> Sem r a) -> Sem r a
- Polysemy.Floodgate: hold :: forall r_axw2. MemberWithError Floodgate r_axw2 => Sem r_axw2 () -> Sem r_axw2 ()
+ Polysemy.Floodgate: hold :: forall r_apIf. MemberWithError Floodgate r_apIf => Sem r_apIf () -> Sem r_apIf ()
- Polysemy.Floodgate: release :: forall r_axw4. MemberWithError Floodgate r_axw4 => Sem r_axw4 ()
+ Polysemy.Floodgate: release :: forall r_apIh. MemberWithError Floodgate r_apIh => Sem r_apIh ()
- Polysemy.KVStore: lookupKV :: forall k_aEOn v_aEOo r_aEQh. MemberWithError (KVStore k_aEOn v_aEOo) r_aEQh => k_aEOn -> Sem r_aEQh (Maybe v_aEOo)
+ Polysemy.KVStore: lookupKV :: forall k_aGzJ v_aGzK r_aGBD. MemberWithError (KVStore k_aGzJ v_aGzK) r_aGBD => k_aGzJ -> Sem r_aGBD (Maybe v_aGzK)
- Polysemy.KVStore: updateKV :: forall k_aEOq v_aEOr r_aEQj. MemberWithError (KVStore k_aEOq v_aEOr) r_aEQj => k_aEOq -> Maybe v_aEOr -> Sem r_aEQj ()
+ Polysemy.KVStore: updateKV :: forall k_aGzM v_aGzN r_aGBF. MemberWithError (KVStore k_aGzM v_aGzN) r_aGBF => k_aGzM -> Maybe v_aGzN -> Sem r_aGBF ()
- Polysemy.Random: random :: forall r_aziz x_azgP. (MemberWithError Random r_aziz, Random x_azgP) => Sem r_aziz x_azgP
+ Polysemy.Random: random :: forall r_aAsA x_aAqQ. (MemberWithError Random r_aAsA, Random x_aAqQ) => Sem r_aAsA x_aAqQ
- Polysemy.Random: randomR :: forall r_aziA x_azgR. (MemberWithError Random r_aziA, Random x_azgR) => (x_azgR, x_azgR) -> Sem r_aziA x_azgR
+ Polysemy.Random: randomR :: forall r_aAsB x_aAqS. (MemberWithError Random r_aAsB, Random x_aAqS) => (x_aAqS, x_aAqS) -> Sem r_aAsB x_aAqS
- Polysemy.SetStore: addS :: forall k_aG4x v_aG4y r_aG7t. MemberWithError (SetStore k_aG4x v_aG4y) r_aG7t => k_aG4x -> v_aG4y -> Sem r_aG7t ()
+ Polysemy.SetStore: addS :: forall k_aJTZ v_aJU0 r_aJWV. MemberWithError (SetStore k_aJTZ v_aJU0) r_aJWV => k_aJTZ -> v_aJU0 -> Sem r_aJWV ()
- Polysemy.SetStore: delS :: forall k_aG4A v_aG4B r_aG7w. MemberWithError (SetStore k_aG4A v_aG4B) r_aG7w => k_aG4A -> v_aG4B -> Sem r_aG7w ()
+ Polysemy.SetStore: delS :: forall k_aJU2 v_aJU3 r_aJWY. MemberWithError (SetStore k_aJU2 v_aJU3) r_aJWY => k_aJU2 -> v_aJU3 -> Sem r_aJWY ()
- Polysemy.SetStore: memberS :: forall k_aG4D v_aG4E r_aG7z. MemberWithError (SetStore k_aG4D v_aG4E) r_aG7z => k_aG4D -> v_aG4E -> Sem r_aG7z Bool
+ Polysemy.SetStore: memberS :: forall k_aJU5 v_aJU6 r_aJX1. MemberWithError (SetStore k_aJU5 v_aJU6) r_aJX1 => k_aJU5 -> v_aJU6 -> Sem r_aJX1 Bool

Files

ChangeLog.md view
@@ -1,5 +1,25 @@ # Changelog for polysemy-zoo ++## 0.6.0.0 (2019-09-05)++- `Final` has been migrated to `polysemy` proper.+    Only `Polysemy.Final.MTL` and experimental features pertaining to+    `Final` remain in `polysemy-zoo`.+- Added `Fresh` effect.+- Added `Tagged` effect.+- Added `MonadCont` constraint absorber which operates via the `Cont` effect.+- Added `runContViaFresh`, which is still under development.+- Added `runReaderFixSem`+- Added `EndState` effect+- Added `RevState` effect+- Added `lowerFinal`+- Added `runFinalSem`+- Added `nonDetToFinal`+- Added `interpretFinalGlobal`+- Added `asyncToIOFinalGlobal`+- Added `resourceToIOFinalGlobal`+ ## 0.5.0.1 (2019-07-25)  - Fixed some bugs with haddock
polysemy-zoo.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: c9916a386c633f322272b00c91e9e16e395cf2d02474c4da8e7bd02ed2828c0f+-- hash: 138a6e0718009344f60c180fe1afffe26e3cf2f9712657e1a0e7c205a9ddebb0  name:           polysemy-zoo-version:        0.5.0.1+version:        0.6.0.0 synopsis:       Experimental, user-contributed effects and interpreters for polysemy description:    Please see the README on GitHub at <https://github.com/isovector/polysemy-zoo#readme> category:       Polysemy@@ -32,28 +32,33 @@       Polysemy.Alias       Polysemy.Capture       Polysemy.ConstraintAbsorber+      Polysemy.ConstraintAbsorber.MonadCont       Polysemy.ConstraintAbsorber.MonadError       Polysemy.ConstraintAbsorber.MonadReader       Polysemy.ConstraintAbsorber.MonadState       Polysemy.ConstraintAbsorber.MonadWriter       Polysemy.Cont       Polysemy.Cont.Internal-      Polysemy.Final-      Polysemy.Final.Async-      Polysemy.Final.Error-      Polysemy.Final.Fixpoint+      Polysemy.EndState+      Polysemy.Final.IO+      Polysemy.Final.IO.Internal+      Polysemy.Final.More       Polysemy.Final.MTL-      Polysemy.Final.Resource+      Polysemy.Final.NonDet       Polysemy.Floodgate+      Polysemy.Fresh       Polysemy.IdempotentLowering       Polysemy.KVStore       Polysemy.Operators       Polysemy.Random+      Polysemy.Reader.More       Polysemy.Redis.Utils+      Polysemy.RevState       Polysemy.SetStore       Polysemy.Several       Polysemy.Shift       Polysemy.Shift.Internal+      Polysemy.Tagged   other-modules:       Paths_polysemy_zoo   hs-source-dirs:@@ -67,13 +72,15 @@     , bytestring >=0.10.8.2 && <0.11     , constraints >=0.10.1 && <0.12     , containers >=0.5 && <0.7+    , contravariant <2     , ghc-prim >=0.5.2 && <0.6     , hedis >=0.10 && <0.13     , mtl >=2.0.1.0 && <3.0.0.0-    , polysemy >=1.0.0.0+    , polysemy >=1.2.0.0     , polysemy-plugin >=0.2     , random >=1.1 && <1.2     , reflection >=2.1.4 && <3.0.0+    , transformers >=0.5.2.0 && <0.6   default-language: Haskell2010  test-suite polysemy-zoo-test@@ -87,6 +94,7 @@       FloodgateSpec       IdempotentLoweringSpec       KVStoreSpec+      RevStateSpec       SeveralSpec       ShiftSpec       Paths_polysemy_zoo@@ -103,13 +111,15 @@     , bytestring >=0.10.8.2 && <0.11     , constraints >=0.10.1 && <0.12     , containers >=0.5 && <0.7+    , contravariant <2     , ghc-prim >=0.5.2 && <0.6     , hedis >=0.10 && <0.13     , hspec >=2.6.0 && <3     , mtl >=2.0.1.0 && <3.0.0.0-    , polysemy >=0.7.0.0+    , polysemy >=1.2.0.0     , polysemy-plugin >=0.2     , polysemy-zoo     , random >=1.1 && <1.2     , reflection >=2.1.4 && <3.0.0+    , transformers >=0.5.2.0 && <0.6   default-language: Haskell2010
src/Polysemy/Capture.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TemplateHaskell, Trustworthy #-} module Polysemy.Capture   (-- * Effect     Capture(..)@@ -25,7 +25,7 @@ import Polysemy.Internal import Polysemy.Internal.Union -import Polysemy.Cont.Internal(Ref(..))+import Polysemy.Cont.Internal (Ref(..))  ----------------------------------------------------------------------------- -- | A less powerful variant of 'Polysemy.Shift.Shift' that may always be@@ -60,7 +60,7 @@ -- -- The provided continuation may fail locally in its subcontinuations. -- It may sometimes become necessary to handle such cases. To do so,--- use 'delimit\'' together with 'reflect' (the reified continuation+-- use 'delimit'' together with 'reflect' (the reified continuation -- is already delimited). reflect :: forall ref s a r         .  Member (Capture ref) r@@ -89,7 +89,7 @@ -- -- The provided continuation may fail locally in its subcontinuations. -- It may sometimes become necessary to handle such cases, in--- which case such failure may be detected by using 'delimit\'' together+-- which case such failure may be detected by using 'delimit'' together -- with the provided continuation (the provided continuation -- is already delimited). capture :: Member (Capture ref) r@@ -99,7 +99,7 @@ {-# INLINE capture #-}  -------------------------------------------------------------------------------- | Runs a 'Capture' effect by providing 'pure '.' Just' as the final+-- | Runs a 'Capture' effect by providing @'pure' '.' 'Just'@ as the final -- continuation. -- -- The final return type is wrapped in a 'Maybe' due to the fact that
+ src/Polysemy/ConstraintAbsorber/MonadCont.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE FlexibleInstances           #-}+{-# LANGUAGE GeneralizedNewtypeDeriving  #-}+{-# LANGUAGE MultiParamTypeClasses       #-}+{-# LANGUAGE UndecidableInstances        #-}++module Polysemy.ConstraintAbsorber.MonadCont+  ( absorbCont+  ) where++import           Data.Coerce+import qualified Control.Monad.Cont.Class as C+import           Polysemy+import           Polysemy.ConstraintAbsorber+import           Polysemy.Cont+++------------------------------------------------------------------------------+-- | Introduce a local 'C.MonadCont' constraint on 'Sem' --- allowing it to+-- interop nicely with MTL.+--+-- @since 0.3.0.0+absorbCont+    :: Member (Cont ref) r+    => (C.MonadCont (Sem r) => Sem r a)+       -- ^ A computation that requires an instance of 'C.MonadCont' for+       -- 'Sem'. This might be something with type @'C.MonadCont' m => m a@.+    -> Sem r a+absorbCont = absorbWithSem @C.MonadCont @Action+  (ContDict callCC)+  (Sub Dict)+{-# INLINEABLE absorbCont #-}+++------------------------------------------------------------------------------+-- | A dictionary of the functions we need to supply+-- to make an instance of Cont+newtype ContDict m = ContDict+  { callCC_ :: forall a b. ((a -> m b) -> m a) -> m a+  }+++------------------------------------------------------------------------------+-- | Wrapper for a monadic action with phantom+-- type parameter for reflection.+-- Locally defined so that the instance we are going+-- to build with reflection must be coherent, that is+-- there cannot be orphans.+newtype Action m s' a = Action (m a)+  deriving (Functor, Applicative, Monad)+++------------------------------------------------------------------------------+-- | Given a reifiable mtl Cont dictionary,+-- we can make an instance of @MonadCont@ for the action+-- wrapped in @Action@.+instance ( Monad m+         , Reifies s' (ContDict m)+         ) => C.MonadCont (Action m s') where+  callCC (cc :: (a -> Action m s' b) -> Action m s' a)+    = Action $ callCC_ (reflect $ Proxy @s') @a @b (coerce cc)+  {-# INLINEABLE callCC #-}
src/Polysemy/Cont.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE Trustworthy #-} module Polysemy.Cont   (-- * Effect     Cont(..)@@ -10,14 +11,18 @@     -- * Interpretations   , runContPure   , runContM-  , runContFinal+  , contToFinal +    -- * Experimental Interpretations+  , runContViaFresh+     -- * Unsafe Interpretations   , runContUnsafe    -- * Prompt types   , Ref(..)   , ExitRef(..)+  , ViaFreshRef   ) where  import Data.Void@@ -27,7 +32,10 @@  import Polysemy.Cont.Internal -import Control.Monad.Cont (MonadCont())+import Polysemy.Error+import Polysemy.Fresh++import Control.Monad.Cont (MonadCont(), ContT(..), runContT) import qualified Control.Monad.Cont as C (callCC)  -----------------------------------------------------------------------------@@ -35,11 +43,8 @@ -- Executing the provided continuation will abort execution. -- -- Using the provided continuation--- will rollback all effectful state back to the point where 'callCC' was invoked,--- unless such state is interpreted in terms of the final--- monad, /or/ the associated interpreter of the effectful state--- is run after 'runContUnsafe', which may be done if the effect isn't--- higher-order.+-- will rollback all local effectful state back to the point where+-- 'callCC' was invoked. -- -- Higher-order effects do not interact with the continuation in any meaningful -- way; i.e. 'Polysemy.Reader.local' or 'Polysemy.Writer.censor' does not affect@@ -47,8 +52,8 @@ -- The only exception to this is if you interpret such effects /and/ 'Cont' -- in terms of the final monad, and the final monad can perform such interactions -- in a meaningful manner.-callCC :: forall ref a r.-          Member (Cont ref) r+callCC :: forall ref r a+       .  Member (Cont ref) r        => ((forall b. a -> Sem r b) -> Sem r a)        -> Sem r a callCC cc = subst (\ref -> cc (jump ref)) pure@@ -77,11 +82,11 @@ -- -- /Beware/: Effects that aren't interpreted in terms of the final monad -- will have local state semantics in regards to 'Cont' effects--- interpreted this way. See 'interpretFinal'.-runContFinal :: (Member (Final m) r, MonadCont m)-             => Sem (Cont (ExitRef m) ': r) a-             -> Sem r a-runContFinal = interpretFinal $ \case+-- interpreted this way. See 'Final'.+contToFinal :: (Member (Final m) r, MonadCont m)+            => Sem (Cont (ExitRef m) ': r) a+            -> Sem r a+contToFinal = interpretFinal $ \case   Jump ref a    -> pure $ enterExit ref a   Subst main cb -> do     main' <- bindS main@@ -89,9 +94,42 @@     s     <- getInitialStateS     pure $ C.callCC $ \exit ->       main' (ExitRef (\a -> cb' (a <$ s) >>= vacuous . exit) <$ s)-{-# INLINE runContFinal #-}+{-# INLINE contToFinal #-}  -----------------------------------------------------------------------------+-- | A highly experimental 'Cont' interpreter that functions+-- through a combination of 'Error' and 'Fresh'. This may be used safely+-- anywhere in the effect stack.+--+-- 'runContViaFresh' is still under development.+-- You're encouraged to experiment with it, but don't rely on it.+-- For best results, use 'runContViaFresh' as the first interpreter you run,+-- such that all other effects are global in respect to it.+--+-- This interpreter may return 'Nothing' if the control flow becomes+-- split into separate, inconsistent parts,+-- such that backtracking fails when trying to invoke continuations.+-- For example, if you reify a continuation inside an+-- 'async':ed thread, and then have that thread return the reified+-- continuation back to the main thread through an 'await', then+-- 'runContViaFresh' will return 'Nothing' upon executing the continuation+-- in the main thread.+runContViaFresh :: forall uniq r a+                 . (Member (Fresh uniq) r, Eq uniq)+                => Sem (Cont (ViaFreshRef uniq) ': r) a+                -> Sem r (Maybe a)+runContViaFresh =+  let+    hush (Right a) = Just a+    hush _         = Nothing+  in+      fmap hush+    . runError+    . (`runContT` pure)+    . runContViaFreshInC+{-# INLINE runContViaFresh #-}++----------------------------------------------------------------------------- -- | Runs a 'Cont' effect by providing 'pure' as the final continuation. -- -- __Beware__: This interpreter will invalidate all higher-order effects of any@@ -99,8 +137,8 @@ -- 'Polysemy.Writer.censor' will be no-ops, 'Polysemy.Error.catch' will fail -- to catch exceptions, and 'Polysemy.Writer.listen' will always return 'mempty'. ----- __You should therefore use 'runContUnsafe' /after/ running all interpreters for--- your higher-order effects.__+-- __You should therefore use 'runContUnsafe' only /after/ running all__+-- __interpreters for your higher-order effects.__ -- -- Note that 'Final' is a higher-order effect, and thus 'runContUnsafe' can't -- safely be used together with 'runFinal'.
src/Polysemy/Cont/Internal.hs view
@@ -1,12 +1,20 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TemplateHaskell, Unsafe #-} module Polysemy.Cont.Internal where +import Data.Functor.Contravariant+ import Polysemy import Polysemy.Internal import Polysemy.Internal.Union+import Polysemy.Fresh+import Polysemy.Error+ import Control.Monad-import Control.Monad.Cont (ContT(..))+import Control.Monad.Trans.Cont hiding (Cont) +import Unsafe.Coerce+import GHC.Exts (Any)+ ----------------------------------------------------------------------------- -- | An effect for abortive continuations. --@@ -63,7 +71,7 @@ -- 'Polysemy.Writer.censor' will be no-ops, 'Polysemy.Error.catch' will fail -- to catch exceptions, and 'Polysemy.Writer.listen' will always return 'mempty'. ----- __You should therefore use 'runContUnsafeWithC' /after/ running all interpreters+-- __You should therefore use 'runContWithCUnsafe' /after/ running all interpreters -- for your higher-order effects.__ runContWithCUnsafe :: (a -> Sem r s) -> Sem (Cont (Ref (Sem r) s) ': r) a -> Sem r s runContWithCUnsafe c (Sem m) = (`runContT` c) $ m $ \u -> case decomp u of@@ -95,4 +103,154 @@ {-# INLINE embedSem #-}  newtype Ref m s a = Ref { runRef :: a -> m s }++instance Contravariant (Ref m s) where+  contramap f ref = Ref (runRef ref . f)+ newtype ExitRef m a = ExitRef { enterExit :: forall b. a -> m b }++instance Contravariant (ExitRef m) where+  contramap f ref = ExitRef $ \a -> enterExit ref (f a)++data ViaFreshRef uniq a = ViaFreshRef { getBacktrackException :: a -> (uniq, Any) }++instance Contravariant (ViaFreshRef uniq) where+  contramap f ref = ViaFreshRef $ \a -> getBacktrackException ref (f a)++{-+  KingoftheHomeless: OK, so let's discuss how this works.+  The idea here is to instead of providing a monadic computation+  to the call of 'callCC' that simply short-circuits everything like+  'ContT' does, we fake that behaviour by instead providing an+  exception to 'callCC', and then try to 'catch' that exception+  on the continuation. If the exception is caught, then we run the+  continuation again. This way, we can get abortive continuations+  without having to scope over a result type variable, avoiding+  the problem that 'runContUnsafe' has, and making it possible+  to weave other effects through without breaking everything.++  Even with that solution, weaving effects through have more problems+  of their own; namely, if we simply lower a+  'forall s. ContT s (Sem r) a' to 'Sem r a', then we effectively+  delimit all higher-order computations. This is bad, because+  if a reified continuation produced within+  the higher-order computation escapes from it,+  then nothing can catch the underlying backtrack exception+  once it is thrown.++  The solution to this is anothor kludge: when weaving other effects through,+  we instead use 'runContViaFreshInCWeave'; this makes use 'ContFreshState'+  as its functorial state, which stores /handlers/ for backtrack exceptions.+  'runContViaFreshInCWeave', in addition to 'catch'ing exceptions on the continuation+  it is given, /also/ returns the handler it uses for the 'catch'.+  This handler is then used by 'runContViaFresh' to catch exceptions on the+  continuation /it/ gets, but can't provide to the higher-order computation.++  I'm astonished that this even remotely works, but it does have some rather+  weird behaviour I haven't completely figured out yet.++  I'm reasonably happy with how 'runContViaFreshInC' looks;+  I'm a lot less happy with 'runContViaFreshInCWeave', I just kinda threw+  it haphazardly. I figure most weirdness stem from issues in+  'runContViaFreshInCWeave', so I need to think it through some more.+-}+-- | Intermediary monadic interpretation used for running 'runContViaFresh'.+-- See source for a discussion on how this works.+runContViaFreshInC :: forall uniq s r a+                    . (Member (Fresh uniq) r, Eq uniq)+                   => Sem (Cont (ViaFreshRef uniq) ': r) a+                   -> ContT s (Sem (Error (uniq, Any) ': r)) a+runContViaFreshInC = usingSem $ \u -> ContT $ \c ->+  case decomp u of+    Right (Weaving e s wv ex _) ->+      case e of+        Subst main cn -> do+          ref <- fresh+          let+            main' = runContViaFreshInC . wv . fmap main . (<$ s)+            cn'   = runContViaFreshInC . wv . fmap cn . (<$ s)+            loop act =+              runContT (ex <$> act) c `catch` \ x@(ref', a') -> do+                if ref == ref' then+                  loop (cn' $ unsafeCoerce a')+                else+                  throw x+          loop $ main' $ ViaFreshRef (\a -> (ref, unsafeCoerce a))+        Jump ref a -> throw (getBacktrackException ref a)+    Left g -> do+      ResAndHandler a rc <- liftSem $+        weave+          (ResAndHandler @uniq @r () throw)+          -- TODO(KingoftheHomeless): is this the distributive law we want?+          (\(ResAndHandler a rc) ->+            runContT+              (runContViaFreshInCWeave a)+              (\x -> pure $+                ResAndHandler+                  x+                  (rc >=> (`runContT` pure) . runContViaFreshInC)+              )+          )+          (Just . getResult)+          (weaken g)+      let loop x = c x `catch` (rc >=> loop)+      loop a++-- | A variant of 'runContViaFreshInC' which it uses when weaving other effects through.+runContViaFreshInCWeave :: forall uniq s r a+                         . (Member (Fresh uniq) r, Eq uniq)+                        => Sem (Cont (ViaFreshRef uniq) ': r) a+                        -> ContT (ContFreshState uniq r s)+                            (Sem (Error (uniq, Any) ': r))+                            a+runContViaFreshInCWeave = usingSem $ \u -> ContT $ \c ->+  case decomp u of+    Right (Weaving e s wv ex _) ->+      case e of+        Subst main cn -> do+          ref <- fresh+          let+            -- TODO(KingoftheHomeless): runContViaFreshInC?+            main' = runContViaFreshInCWeave . wv . fmap main . (<$ s)+            cn'   = runContViaFreshInCWeave . wv . fmap cn . (<$ s)+            loop act =+              runContT (ex <$> act) c `catch` \ x@(ref', a') -> do+                if ref == ref' then+                  loop (cn' $ unsafeCoerce a')+                else+                  throw x+          ResAndHandler res h <-+            loop $ main' $ ViaFreshRef (\a -> (ref, unsafeCoerce a))+          return $ ResAndHandler res+              -- TODO(KingoftheHomeless): This handler is dubious.+            $ \x -> fmap getResult $ loop $ ContT $ \_ -> fmap (`ResAndHandler` h) (h x)+        Jump ref a -> throw (getBacktrackException ref a)+    Left g -> do+      ResAndHandler a h <- liftSem $+        weave+          (ResAndHandler @uniq @r () throw)+          (\(ResAndHandler a rc) ->+            runContT+              (runContViaFreshInCWeave a)+              (\x -> pure $+                ResAndHandler+                  x+                  (rc >=> (`runContT` pure) . runContViaFreshInC)+              )+          )+          (Just . getResult)+          (weaken g)+      let loop x = c x `catch` (h >=> loop)+      ResAndHandler res h' <- loop a+      -- TODO(KingoftheHomeless): This handler is dubious.+      return (ResAndHandler res $ \x -> (h' x `catch` (h >=> fmap getResult . loop)))++-- | This is the effectful state used by 'runContViaFreshInC' when weaving through+-- other effectful actions. The point of it is to avoid delimiting computations+-- in higher-order effects, by having them return a handler which may be used+-- to intercept backtrack exceptions of the current continuation.+data ContFreshState uniq r a = ResAndHandler {+    getResult :: a+  , getHandler :: (uniq, Any) -> Sem (Error (uniq, Any) ': r) a+  }+  deriving Functor
+ src/Polysemy/EndState.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE TemplateHaskell #-}+module Polysemy.EndState+  (-- * Effect+    EndState(..)++    -- * Actions+  , getEndState++    -- * Interpretations+  , runEndState+  , runEndAtomicState+  ) where++import Polysemy+import Polysemy.Fixpoint+import Polysemy.Reader+import Polysemy.Reader.More++import Polysemy.State+import Polysemy.AtomicState+++-----------------------------------------------------------------------------+-- | An effect for getting the end state of a computation in advance.+data EndState s m a where+  GetEndState :: EndState s m s++makeSem ''EndState++-----------------------------------------------------------------------------+-- | Runs an 'EndState' effect by getting the state after the computation+-- has finished, and providing it recursively back to calls of 'getEndState'.+runEndState :: (Member (State s) r, Member Fixpoint r)+            => Sem (EndState s ': r) a+            -> Sem r a+runEndState =+    runReaderFixSem get+  . reinterpret (\GetEndState -> ask)+++-----------------------------------------------------------------------------+-- | Like 'runEndState', but for 'AtomicState' rather than 'State'.+runEndAtomicState+  :: (Member (AtomicState s) r, Member Fixpoint r)+  => Sem (EndState s ': r) a+  -> Sem r a+runEndAtomicState =+    runReaderFixSem atomicGet+  . reinterpret (\GetEndState -> ask)
− src/Polysemy/Final.hs
@@ -1,284 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}-module Polysemy.Final-  (-    -- * Effect-    Final(..)--    -- * Actions-  , withWeaving-  , withStrategic-  , embedFinal--    -- * Combinators for Interpreting to the Final Monad-  , interpretFinal--    -- * Strategy-    -- | Strategy is a domain-specific language very similar to @Tactics@-    -- (see 'Tactical'), and is used to describe how higher-order effects-    -- are threaded down to the final monad.-    ---    -- Much like @Tactics@, computations can be run and threaded-    -- through the use of 'runS' and 'bindS', and first-order constructors-    -- may use 'pureS'. In addition, 'liftS' may be used to-    -- lift actions of the final monad.-    ---    -- Unlike @Tactics@, the final return value within a `Strategic`-    -- must be a monadic value of the target monad-    -- with the functorial state wrapped inside of it.-  , Strategic-  , WithStrategy-  , pureS-  , liftS-  , runS-  , bindS-  , getInspectorS-  , getInitialStateS--    -- * Interpretations-  , runFinal-  , runFinalLift-  , runFinalLiftIO-  ) where--import Data.Functor.Identity--import Polysemy-import Data.Functor.Compose-import Polysemy.Internal-import Polysemy.Internal.Tactics-import Polysemy.Internal.Union-import Control.Monad-import Control.Monad.IO.Class---------------------------------------------------------------------------------- | An effect for embedding higher-order effects in the final target monad--- of the effect stack.------ This is very useful for writing interpreters that interpret higher-order--- effects in terms of the final monad - however, these interpreters--- are subject to very different semantics than regular ones.------ For more information, see 'interpretFinal'.-data Final m z a where-  WithWeaving :: (forall f.-                      Functor f-                   => f ()-                   -> (forall x. f (z x) -> m (f x))-                   -> (forall x. f x -> Maybe x)-                   -> m (f a)-                 )-              -> Final m z a--makeSem_ ''Final---------------------------------------------------------------------------------- | Allows for embedding higher-order actions of the final monad--- by providing the means of explicitly threading effects through @'Sem' r@--- to the final monad.------ Consider using 'withStrategic' instead,--- as it provides a more user-friendly interface to the same power.------ You are discouraged from using 'withWeaving' directly in application code,--- as it ties your application code directly to the underlying monad.-withWeaving :: forall m a r-            .   Member (Final m) r-            => (forall f.-                    Functor f-                 => f ()-                 -> (forall x. f (Sem r x) -> m (f x))-                 -> (forall x. f x -> Maybe x)-                 -> m (f a)-               )-            -> Sem r a---------------------------------------------------------------------------------- | 'withWeaving' admits an implementation of 'sendM'.------ Just like 'sendM', you are discouraged from using this in application code.-embedFinal :: Functor m => Member (Final m) r => m a -> Sem r a-embedFinal m = withWeaving $ \s _ _ -> (<$ s) <$> m----------------------------------------------------------------------------------- | Allows for embedding higher-order actions of the final monad--- by providing the means of explicitly threading effects through 'Sem r'--- to the final monad. This is done through the use of the 'Strategic'--- environment.------ You are discouraged from using 'withStrategic' in application code,--- as it ties your application code directly to the underlying monad.-withStrategic :: Member (Final m) r => Strategic m (Sem r) a -> Sem r a-withStrategic strat = withWeaving $ \s wv ins -> runStrategy s wv ins strat----------------------------------------------------------------------------------- | Like 'interpretH', but may be used to--- interpret higher-order effects in terms of the final monad.------ /Beware/: Any interpreters built using this (or 'Final' in general)--- will /not/ respect local/global state semantics based on the order of--- interpreters run. You should signal interpreters that make use of--- 'Final' by adding a "-Final" suffix to the names of these.------ State semantics of effects that are /not/--- interpreted in terms of the final monad will always--- appear local to effects that are interpreted in terms of the final monad.------ State semantics between effects that are interpreted in terms of the final monad--- depend on the final monad. I.e. if the final monad is a monad transformer stack,--- then state semantics will depend on the order monad transformers are stacked.-interpretFinal-    :: forall e m r a-    .  (Member (Final m) r, Functor m)-    => (forall x n. e n x -> Strategic m n x)-    -> Sem (e ': r) a-    -> Sem r a-interpretFinal n =-  let-    go :: Sem (e ': r) x -> Sem r x-    go (Sem sem) = sem $ \u -> case decomp u of-      Right (Weaving e s wv ex ins) ->-        fmap ex $ withWeaving $ \s' wv' ins'-          -> fmap getCompose $-                runStrategy-                  (Compose (s <$ s'))-                  (fmap Compose . wv' . fmap (go . wv) . getCompose)-                  (ins' . getCompose >=> ins)-                  (n e)-      Left g -> liftSem (hoist go g)-    {-# INLINE go #-}-  in-    go-{-# INLINE interpretFinal #-}----------------------------------------------------------------------------------- | 'Strategic' is an environment in which you're capable of explicitly--- threading higher-order effect states to the final monad.--- This is based upon @Tactics@, (see 'Tactical'), and usage--- is extremely similar.-type Strategic m n a = forall f. Functor f => Sem (WithStrategy m f n) (m (f a))--type WithStrategy m f n = WithTactics (Embed m) f n '[]----------------------------------------------------------------------------------- | Get a natural transformation capable of potentially inspecting values--- inside of @f@. Binding the result of 'getInspectorS' produces a function that--- can sometimes peek inside values returned by 'bindS'.------ This is often useful for running callback functions that are not managed by--- polysemy code.------ See also 'getInspectorT'-getInspectorS :: Sem (WithStrategy m f n) (Inspector f)-getInspectorS = getInspectorT-{-# INLINE getInspectorS #-}----------------------------------------------------------------------------------- | Get the stateful environment of the world at the moment the--- target monad is to be run.--- Prefer 'pureS', 'runS' or 'bindS' instead of using this function--- directly.-getInitialStateS :: Sem (WithStrategy m f n) (f ())-getInitialStateS = getInitialStateT-{-# INLINE getInitialStateS #-}----------------------------------------------------------------------------------- | Embed a value into 'Strategic'.-pureS :: Applicative m => a -> Strategic m n a-pureS = fmap pure . pureT-{-# INLINE pureS #-}----------------------------------------------------------------------------------- | Lifts an action of the final monad into 'Strategic'.------ Note: you don't need to use this function if you already have a monadic--- action with the functorial state woven into it, by the use of--- 'runS' or 'bindS'.--- In these cases, you need only use 'pure' to embed the action into the--- 'Strategic' environment.-liftS :: Functor m => m a -> Strategic m n a-liftS m = do-  s <- getInitialStateS-  pure $ fmap (<$ s) m-{-# INLINE liftS #-}----------------------------------------------------------------------------------- | Lifts a monadic action into the stateful environment, in terms--- of the final monad.--- The stateful environment will be the same as the one that the target monad--- is initially run in.--- Use 'bindS'  if you'd prefer to explicitly manage your stateful environment.-runS :: Monad m => n a -> Sem (WithStrategy m f n) (m (f a))-runS = fmap runM . runT-{-# INLINE runS #-}----------------------------------------------------------------------------------- | Embed a kleisli action into the stateful environment, in terms of the final--- monad. You can use 'bindS' to get an effect parameter of the form @a -> n b@--- into something that can be used after calling 'runS' on an effect parameter--- @n a@.-bindS :: Monad m => (a -> n b) -> Sem (WithStrategy m f n) (f a -> m (f b))-bindS = fmap (runM .) . bindT-{-# INLINE bindS #-}----------------------------------------------------------------------------------- | Internal function to process Strategies in terms of 'withWeaving'.-runStrategy :: Functor f-            => f ()-            -> (forall x. f (n x) -> m (f x))-            -> (forall x. f x -> Maybe x)-            -> Sem (WithStrategy m f n) a-            -> a-runStrategy s wv ins (Sem m) = runIdentity $ m $ \u -> case extract u of-  Weaving e s' _ ex' _ -> Identity $ ex' $ (<$ s') $ case e of-    GetInitialState -> s-    HoistInterpretation na -> embed . wv . fmap na-    GetInspector -> Inspector ins-{-# INLINE runStrategy #-}----------------------------------------------------------------------------------- | Lower a 'Sem' containing only a lifted, final monad into that monad.--- The appearance of 'Lift' as the final effect--- is to allow the use of operations that rely on a @'LastMember' ('Lift' m)@--- constraint.-runFinal :: Monad m => Sem '[Final m, Embed m] a -> m a-runFinal = usingSem $ \u -> case decomp u of-  Right (Weaving (WithWeaving wav) s wv ex ins) ->-    ex <$> wav s (runFinal . wv) ins-  Left g -> case extract g of-    Weaving (Embed m) s _ ex _ -> ex . (<$ s) <$> m-{-# INLINE runFinal #-}----------------------------------------------------------------------------------- | Lower a 'Sem' containing two lifted monad into the final monad,--- by interpreting one of the monads in terms of the other one.------ This allows for the use of operations that rely on a @'LastMember' ('Lift' m)@--- constraint, as long as @m@ can be transformed to the final monad;--- but be warned, this breaks the implicit contract of @'LastMember' ('Lift' m)@--- that @m@ /is/ the final monad, so depending on the final monad and operations--- used, 'runFinalLift' may become /unsafe/.------ For example, 'runFinalLift' is unsafe with 'Polysemy.Async.asyncToIO' if--- the final monad is non-deterministic, or a continuation--- monad.-runFinalLift :: Monad m-              => (forall x. n x -> m x)-              -> Sem [Final m, Embed m, Embed n] a-              -> m a-runFinalLift nat = usingSem $ \u -> case decomp u of-  Right (Weaving (WithWeaving wav) s wv ex ins) ->-    ex <$> wav s (runFinalLift nat . wv) ins-  Left g -> case decomp g of-    Right (Weaving (Embed m) s _ ex _) -> ex . (<$ s) <$> m-    Left g' -> case extract g' of-      Weaving (Embed n) s _ ex _ -> ex . (<$ s) <$> nat n-{-# INLINE runFinalLift #-}----------------------------------------------------------------------------------- | 'runFinalLift', specialized to transform 'IO' to a 'MonadIO'.-runFinalLiftIO :: MonadIO m-               => Sem [Final m, Embed m, Embed IO] a-               -> m a-runFinalLiftIO = runFinalLift liftIO-{-# INLINE runFinalLiftIO #-}
− src/Polysemy/Final/Async.hs
@@ -1,38 +0,0 @@-module Polysemy.Final.Async-  (-    module Polysemy.Async-  , module Polysemy.Final-  , runAsyncFinal-  ) where--import qualified Control.Concurrent.Async as A--import Polysemy-import Polysemy.Async-import Polysemy.Final----------------------------------------------------------------------------------- | Run an 'Async' effect through final 'IO'------ This can be used as an alternative to 'lowerAsync'.------ /Beware/: Effects that aren't interpreted in terms of 'IO'--- will have local state semantics in regards to 'Async' effects--- interpreted this way. See 'interpretFinal'.------ Notably, unlike 'asyncToIO', this is not consistent with--- 'Polysemy.State.State' unless 'Polysemy.State.runStateInIORef' is used.--- State that seems like it should be threaded globally throughout the `Async`--- /will not be./------ Prefer 'asyncToIO' unless its unsafe or inefficient in the context of your--- application.-runAsyncFinal :: Member (Final IO) r-              => Sem (Async ': r) a-              -> Sem r a-runAsyncFinal = interpretFinal $ \case-  Async m -> do-    ins <- getInspectorS-    m' <- runS m-    liftS $ A.async (inspect ins <$> m')-  Await a -> liftS (A.wait a)
− src/Polysemy/Final/Error.hs
@@ -1,63 +0,0 @@-module Polysemy.Final.Error-  (-    module Polysemy.Error-  , module Polysemy.Final-  , runErrorInIOFinal-  ) where--import           Control.Exception hiding (throw, catch)-import qualified Control.Exception as X-import           Data.Typeable (Typeable, typeRep)-import           Polysemy-import           Polysemy.Final-import           Polysemy.Error----------------------------------------------------------------------------------- | Run an 'Error' effect as an 'IO' 'Exception'.------ This can be used as an alternative to 'runErrorInIO'------ /Beware/: Effects that aren't interpreted in terms of 'IO'--- will have local state semantics in regards to 'Error' effects--- interpreted this way. See 'interpretFinal'.-runErrorInIOFinal-    :: ( Typeable e-       , Member (Final IO) r-       )-    => Sem (Error e ': r) a-    -> Sem r (Either e a)-runErrorInIOFinal sem = withStrategic $ do-  m' <- runS (runErrorAsExcFinal sem)-  s <- getInitialStateS-  pure $-    either-      ((<$ s) . Left . unwrapExc)-      (fmap Right)-    <$> try m'-{-# INLINE runErrorInIOFinal #-}--runErrorAsExcFinal-    :: forall e r a-    .  ( Typeable e-       , Member (Final IO) r-       )-    => Sem (Error e ': r) a-    -> Sem r a-runErrorAsExcFinal = interpretFinal $ \case-  Throw e   -> pure $ throwIO $ WrappedExc e-  Catch m h -> do-    m' <- runS m-    h' <- bindS h-    s  <- getInitialStateS-    pure $ X.catch m' $ \(se :: WrappedExc e) ->-      h' (unwrapExc se <$ s)-{-# INLINE runErrorAsExcFinal #-}---newtype WrappedExc e = WrappedExc { unwrapExc :: e }-  deriving (Typeable)--instance Typeable e => Show (WrappedExc e) where-  show = mappend "WrappedExc: " . show . typeRep--instance (Typeable e) => Exception (WrappedExc e)
− src/Polysemy/Final/Fixpoint.hs
@@ -1,23 +0,0 @@-module Polysemy.Final.Fixpoint-  (-    module Polysemy.Fixpoint-  , module Polysemy.Final-  , runFixpointFinal-  ) where--import Polysemy-import Polysemy.Final-import Polysemy.Fixpoint--import Control.Monad.Fix---------------------------------------------------------------------------------- | Run a 'Fixpoint' effect through a final 'MonadFix'-runFixpointFinal :: (Member (Final m) r, MonadFix m)-                 => Sem (Fixpoint ': r) a-                 -> Sem r a-runFixpointFinal = interpretFinal $ \case-  Fixpoint f -> do-    f' <- bindS f-    pure $ mfix f'-{-# INLINE runFixpointFinal #-}
+ src/Polysemy/Final/IO.hs view
@@ -0,0 +1,57 @@+module Polysemy.Final.IO+  (+    -- * Combinators for Interpreting to the Final Monad+    interpretFinalGlobal++    -- * Interpretations for other effects+  , asyncToIOFinalGlobal+  , resourceToIOFinalGlobal+  ) where++import qualified Control.Concurrent.Async as A+import qualified Control.Exception as X++import Polysemy+import Polysemy.Final+import Polysemy.Final.IO.Internal+import Polysemy.Async+import Polysemy.Resource++------------------------------------------------------------------------------+-- | 'asyncToIOFinal' implemented using 'interpretFinalGlobal'.+--+-- This behaves semantically very much like 'asyncToIO',+-- but doesn't need to spin up an interpreter thread, making it more+-- efficient (but not any more safe).+asyncToIOFinalGlobal :: Member (Final IO) r+                     => Sem (Async ': r) a+                     -> Sem r a+asyncToIOFinalGlobal = interpretFinalGlobal $ \case+  Async m -> do+    ins <- getInspectorS+    m'  <- runS m+    liftS $ A.async (inspect ins <$> m')+  Await a -> liftS (A.wait a)+{-# INLINE asyncToIOFinalGlobal #-}+------------------------------------------------------------------------------+-- | 'resourceToIOFinal' implemented using 'interpretFinalGlobal'.+--+-- This behaves semantically very much like 'resourceToIO',+-- but doesn't need to spin up an interpreter thread,+-- making it more efficient (but not any more safe).+resourceToIOFinalGlobal :: Member (Final IO) r+                        => Sem (Resource ': r) a+                        -> Sem r a+resourceToIOFinalGlobal = interpretFinalGlobal $ \case+  Bracket alloc dealloc use -> do+    a <- runS  alloc+    d <- bindS dealloc+    u <- bindS use+    pure $ X.bracket a d u++  BracketOnError alloc dealloc use -> do+    a <- runS  alloc+    d <- bindS dealloc+    u <- bindS use+    pure $ X.bracketOnError a d u+{-# INLINE resourceToIOFinalGlobal #-}
+ src/Polysemy/Final/IO/Internal.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE TemplateHaskell #-}+module Polysemy.Final.IO.Internal where++import Data.Functor.Compose+import Data.Maybe++import Control.Concurrent.MVar+import Control.Exception+import Control.Monad+import Control.Monad.Trans.Maybe++import Polysemy+import Polysemy.Final+import Polysemy.Internal+import Polysemy.Internal.Union+import Polysemy.Internal.Strategy++------------------------------------------------------------------------------+-- | Like 'interpretFinal' specialized to 'IO', but also tries very hard+-- to preserve state semantics dependant on the order interpreters are run,+-- adressing the primary issue with 'Final'.+--+-- Semantically, interpreters written using this behave very much as+-- though they were written using 'withLowerToIO'.+-- However, this does not need to spawn an interpreter thread, making+-- it more efficient (but not any more safe.)+--+-- 'interpretFinalGlobal' 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.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@.+--+-- The assumption holds true for all interpreters featured in polysemy,+-- and is presumably always true for any properly implemented interpreter.+-- 'interpretFinalGlobal' may throw an exception if it is used together with an+-- interpreter that uses 'Polysemy.Internal.Union.weave' improperly.+interpretFinalGlobal+    :: forall e a r+     . Member (Final IO) r+    => (forall x n. e n x -> Strategic IO n x)+    -> Sem (e ': r) a+    -> Sem r a+interpretFinalGlobal f sem = withWeavingToFinal $ \s wv ins -> do+  st  <- newMVar s+  res <- runMaybeT $ runViaFinalGlobal st wv ins f sem+  s'  <- readMVar st+  return (fromMaybe bomb res <$ s')+{-# INLINE interpretFinalGlobal #-}++runViaFinalGlobal :: (Member (Final IO) r, Functor f)+                  => MVar (f ())+                  -> (forall x. f (Sem r x) -> IO (f x))+                  -> (forall x. f x -> Maybe x)+                  -> ( forall x n+                     . e n x+                    -> Strategic IO n x+                     )+                  -> Sem (e ': r) a+                  -> MaybeT IO a+runViaFinalGlobal st wv ins f = usingSem $ \u -> case decomp u of+  Right (Weaving e s' wv' ex ins') ->+    fmap ex $ MaybeT $ fmap getCompose $ runStrategy (f e)+          (Compose (Just s'))+          (  maybe+              (pure (Compose Nothing))+              (  fmap Compose+               . runMaybeT+               . runViaFinalGlobal st wv ins f+               . wv'+              )+           . getCompose+          )+          (getCompose >=> ins')+  Left g -> case prj g of+      Just (Weaving (WithWeavingToFinal wav) s' wv' ex' ins') ->+        MaybeT $ fmap (fmap ex' . getCompose) $+          wav+            (Compose (Just s'))+            (  maybe+                (pure (Compose Nothing))+                ( fmap Compose+                . runMaybeT+                . runViaFinalGlobal st wv ins f+                . wv'+                )+             . getCompose+            )+            (getCompose >=> ins')+      _ -> MaybeT $ mask $ \restore -> do+        -- TODO(KingoftheHomeless): Figure out a solution to polysemy issue #205.+        -- Although we're using a different mechanism, the exact same problem manifests+        -- here.+        s   <- takeMVar st+        res <- restore (wv (liftSem (hoist (interpretFinalGlobal f) g) <$ s))+          `onException` putMVar st s+        putMVar st (() <$ res)+        return $ ins res+{-# INLINE runViaFinalGlobal #-}++bomb :: a+bomb = error+  "interpretFinalGlobal: Uninspectable functorial state \+                        \still carried a result. You're likely using an interpreter \+                        \that uses 'weave' improperly. \+                        \See documentation for more information."
src/Polysemy/Final/MTL.hs view
@@ -1,10 +1,10 @@ module Polysemy.Final.MTL   (     module Polysemy.Final-  , runErrorFinal-  , runReaderFinal-  , runStateFinal-  , runWriterFinal+  , errorToFinal+  , readerToFinal+  , stateToEmbed+  , writerToFinal   ) where  import Control.Monad.Error.Class hiding (Error)@@ -24,64 +24,64 @@ -- -- /Beware/: Effects that aren't interpreted in terms of the final -- monad will have local state semantics in regards to 'Error' effects--- interpreted this way. See 'interpretFinal'.-runErrorFinal :: (Member (Final m) r, MonadError e m)-              => Sem (Error e ': r) a-              -> Sem r a-runErrorFinal = interpretFinal $ \case+-- interpreted this way. See 'Final'.+errorToFinal :: (Member (Final m) r, MonadError e m)+             => Sem (Error e ': r) a+             -> Sem r a+errorToFinal = interpretFinal $ \case   Throw e   -> pure $ throwError e   Catch m h -> do     m' <- runS m     h' <- bindS h-    s <- getInitialStateS+    s  <- getInitialStateS     pure $ m' `catchError` (h' . (<$ s))-{-# INLINE runErrorFinal #-}+{-# INLINE errorToFinal #-}  ----------------------------------------------------------------------------- -- | Run a 'Reader' effect through a final 'MonadReader' -- -- /Beware/: Effects that aren't interpreted in terms of the final -- monad will have local state semantics in regards to 'Reader' effects--- interpreted this way. See 'interpretFinal'.-runReaderFinal :: (Member (Final m) r, MonadReader i m)-               => Sem (Reader i ': r) a-               -> Sem r a-runReaderFinal = interpretFinal $ \case+-- interpreted this way. See 'Final'.+readerToFinal :: (Member (Final m) r, MonadReader i m)+              => Sem (Reader i ': r) a+              -> Sem r a+readerToFinal = interpretFinal $ \case   Ask       -> liftS ask   Local f m -> do     m' <- runS m     pure $ local f m'-{-# INLINE runReaderFinal #-}+{-# INLINE readerToFinal #-}  -------------------------------------------------------------------------------- | Run a 'State' effect through a 'MonadState'+-- | Run a 'State' effect in terms of an underlying 'MonadState' instance ----- Despite the name, the target monad need not actually be the final--- monad. The "-Final" suffix reflects that this interpreter--- has the unusual semantics of interpreters that runs+-- Although this is not a 'Final' interpreter, as the target monad need not+-- actually be the final monad, 'stateToEmbed' still possesses the+-- unusual semantics of interpreters that runs -- effects by embedding them into another monad. ----- /Beware/: Effects that aren't interpreted in terms of the final+-- /Beware/: Effects that aren't interpreted in terms of the embedded -- monad will have local state semantics in regards to 'State' effects--- interpreted this way. See 'interpretFinal'.-runStateFinal :: (Member (Embed m) r, MonadState s m)-               => Sem (State s ': r) a-               -> Sem r a-runStateFinal = interpret $ \case+-- interpreted this way. See 'Final'.+stateToEmbed :: (Member (Embed m) r, MonadState s m)+             => Sem (State s ': r) a+             -> Sem r a+stateToEmbed = interpret $ \case   Get   -> embed get   Put s -> embed (put s)-{-# INLINE runStateFinal #-}+{-# INLINE stateToEmbed #-}  ----------------------------------------------------------------------------- -- | Run a 'Writer' effect through a final 'MonadWriter' -- -- /Beware/: Effects that aren't interpreted in terms of the final -- monad will have local state semantics in regards to 'Writer' effects--- interpreted this way. See 'interpretFinal'.-runWriterFinal :: (Member (Final m) r, MonadWriter o m)-               => Sem (Writer o ': r) a-               -> Sem r a-runWriterFinal = interpretFinal $ \case+-- interpreted this way. See 'Final'.+writerToFinal :: (Member (Final m) r, MonadWriter o m)+              => Sem (Writer o ': r) a+              -> Sem r a+writerToFinal = interpretFinal $ \case   Tell s    -> liftS (tell s)   Listen m -> do     m' <- runS m@@ -94,4 +94,4 @@       t <- m'       let f = maybe id fst (inspect ins t)       pure (fmap snd t, f)-{-# INLINE runWriterFinal #-}+{-# INLINE writerToFinal #-}
+ src/Polysemy/Final/More.hs view
@@ -0,0 +1,32 @@+module Polysemy.Final.More where++import Polysemy+import Polysemy.Internal+import Polysemy.Internal.Union+import Polysemy.Final++------------------------------------------------------------------------------+-- | Run a @'Final' ('Sem' r)@ effect if the remaining effect stack is @r@.+--+-- This is sometimes useful for interpreters that make use of+-- 'reinterpret', 'raiseUnder', or any of their friends.+runFinalSem :: Sem (Final (Sem r) ': r) a -> Sem r a+runFinalSem = usingSem $ \u -> case decomp u of+  Right (Weaving (WithWeavingToFinal wav) s wv ex ins) ->+    ex <$> wav s (runFinalSem . wv) ins+  Left g -> liftSem (hoist runFinalSem g)+{-# INLINE runFinalSem #-}++------------------------------------------------------------------------------+-- | Run a @'Final' m@ effect by providing an explicit lowering function.+--+-- /Beware/: The lowering function may be invoked multiple times, so+-- __don't do any initialization work inside the lowering function__:+-- it will be duplicated.+lowerFinal :: Member (Embed m) r+           => (forall x. Sem r x -> m x)+           -> Sem (Final m ': r) a+           -> Sem r a+-- TODO(KingoftheHomeless): Write everything out for efficiency?+lowerFinal f = runFinalSem . finalToFinal embed f . raiseUnder+{-# INLINE lowerFinal #-}
+ src/Polysemy/Final/NonDet.hs view
@@ -0,0 +1,28 @@+module Polysemy.Final.NonDet+  (+    module Polysemy.NonDet+  , nonDetToFinal+  ) where++import Control.Applicative++import Polysemy+import Polysemy.NonDet+import Polysemy.Final++-----------------------------------------------------------------------------+-- | Run an 'NonDet' effect through a final 'Alternative'+--+-- /Beware/: Effects that aren't interpreted in terms of the final+-- monad will have local state semantics in regards to 'NonDet' effects+-- interpreted this way. See 'Final'.+nonDetToFinal :: (Member (Final m) r, Alternative m)+              => Sem (NonDet ': r) a+              -> Sem r a+nonDetToFinal = interpretFinal $ \case+  Empty -> pure empty+  Choose left right -> do+    left'  <- runS left+    right' <- runS right+    pure $ left' <|> right'+{-# INLINE nonDetToFinal #-}
− src/Polysemy/Final/Resource.hs
@@ -1,45 +0,0 @@-module Polysemy.Final.Resource-  (-    module Polysemy.Resource-  , module Polysemy.Final-  , runResourceFinal-  ) where--import qualified Control.Exception as X-import           Polysemy-import           Polysemy.Resource-import           Polysemy.Final------------------------------------------------------------------------------------ | Run a 'Resource' effect in terms of 'X.bracket' through final 'IO'------ This can be used as an alternative to 'runResourceInIO'------ /Beware/: Effects that aren't interpreted in terms of 'IO'--- will have local state semantics in regards to 'Resource' effects--- interpreted this way. See 'interpretFinal'.------ Notably, unlike 'runResourceBase', this is not consistent with--- 'Polysemy.State.State' unless 'Polysemy.State.runStateInIORef' is used.--- State that seems like it should be threaded globally throughout 'bracket's--- /will not be./------ Prefer 'runResourceBase' unless it's unsafe or inefficient in the context of--- your application.-runResourceFinal :: Member (Final IO) r-                 => Sem (Resource ': r) a-                 -> Sem r a-runResourceFinal = interpretFinal $ \case-  Bracket alloc dealloc use -> do-    a <- runS  alloc-    d <- bindS dealloc-    u <- bindS use-    pure $ X.bracket a d u--  BracketOnError alloc dealloc use -> do-    a <- runS  alloc-    d <- bindS dealloc-    u <- bindS use-    pure $ X.bracketOnError a d u-{-# INLINE runResourceFinal #-}
+ src/Polysemy/Fresh.hs view
@@ -0,0 +1,118 @@+{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving, TemplateHaskell, Trustworthy #-}+module Polysemy.Fresh+  (-- * Effect+    Fresh(..)++    -- * Actions+  , fresh++    -- * Interpretations+  , freshToIO++    -- * Unsafe Interpretations+  , runFreshEnumUnsafe+  , runFreshUnsafePerformIO+  ) where++import Data.Unique++import Polysemy.Internal+import Polysemy.Internal.Union+import System.IO.Unsafe (unsafePerformIO)+import Polysemy+import Polysemy.State++-----------------------------------------------------------------------------+-- | An effect for creating unique objects which may be used as references,+-- a la 'Unique'. Polymorphic code making use of 'Fresh' is expected+-- to place constraints upon @uniq@ as necessary.+--+-- Any interpreter for 'Fresh' has the responsibilty of ensuring+-- that any call to 'fresh' produces an object that /never/+-- compares equal to an object produced by a previous call to 'fresh'.+data Fresh uniq m a where+  Fresh :: Fresh uniq m uniq++makeSem ''Fresh++-----------------------------------------------------------------------------+-- | Runs a 'Fresh' effect through generating 'Unique's using 'IO'.+freshToIO :: Member (Embed IO) r+          => Sem (Fresh Unique ': r) a+          -> Sem r a+freshToIO = interpret $ \Fresh -> embed newUnique+{-# INLINE freshToIO #-}++-----------------------------------------------------------------------------+-- | Run a 'Fresh' effect purely by specifying an 'Enum' to be used as the+-- type of unique objects.+--+-- __Beware:__ This is safe only if:+--+--   1. This is run after all interpreters which may revert local state+--      or produce multiple, inconsistent instances of local state.+--      This includes interpreters that may backtrack or produce multiple results+--      (such as 'Polysemy.Error.runError' or 'Polysemy.NonDet.runNonDet').+--+--   2. You don't use any interpreter which may cause the final monad+--      to revert local state or produce multiple, inconsistent instances of local+--      state. This includes certain 'Polysemy.Final.Final'/@lower-@ interpeters+--      such as 'Polysemy.Error.lowerError' or 'Polysemy.Final.MTL.errorToFinal',+--      as well as interpreters for 'Polysemy.Async.Async'.+--+-- Prefer 'freshToIO' whenever possible.+-- If you can't use 'runFreshEnumUnsafe' safely, nor use 'freshToIO', consider+-- 'runFreshUnsafePerformIO'.+runFreshEnumUnsafe :: forall n a r+                    . Enum n+                   => Sem (Fresh n ': r) a+                   -> Sem r a+runFreshEnumUnsafe =+    (fmap snd .)+  $ (runState @n (toEnum 0) .)+  $ reinterpret+  $ \Fresh -> do+    s <- get+    put $! succ s+    return s+{-# INLINE runFreshEnumUnsafe #-}++-----------------------------------------------------------------------------+-- | Runs a 'Fresh' effect through generating 'Unique's using+-- 'unsafePerformIO'.+--+-- Ironically, despite the fact that this uses 'unsafePerformIO', and+-- 'runFreshUnsafe' uses no unsafe operations whatsoever, this is still+-- typically safer to use than 'runFreshUnsafe', although 'runFreshUnsafe'+-- is perhaps more efficient.+--+-- The worst thing that this particular use of 'unsafePerformIO' could result+-- in is the loss of referential transparency, as rerunning an interpreter stack+-- using 'runFreshUnsafePerformIO' will create different 'Unique's. This should+-- never matter.+--+-- This could be potentially be less efficient than 'runFreshUnsafe'.+--+-- If you ever observe that multiple invocations of 'fresh' produce the same+-- 'Unique' under 'runFreshUnsafePerformIO', then open an issue over at the+-- GitHub repository.+runFreshUnsafePerformIO :: Sem (Fresh Unique ': r) a+                        -> Sem r a+runFreshUnsafePerformIO = usingSem $ \u ->+  case decomp u of+    Right (Weaving Fresh s _ ex _) -> do+      let !uniq = unsafePerformIO (newUnique' u)+          {-# NOINLINE uniq #-}+      pure $ ex (uniq <$ s)+    Left g -> liftSem (hoist runFreshUnsafePerformIO g)+-- KingoftheHomeless: I've tried very hard to prevent optimizations from+-- sharing the call to 'unsafePerformIO'.+-- The inlining of 'interpret' is so that I can give+-- 'u' to 'newUnique'', and thus prevent 'uniq' from floating outside the+-- lambda. This interpreter might even be safe to INLINE, but I'm not taking+-- any chances.+{-# NOINLINE runFreshUnsafePerformIO #-}++newUnique' :: Union (Fresh Unique ': r) (Sem (Fresh Unique ': r)) a -> IO Unique+newUnique' (Union _ _) = newUnique+{-# NOINLINE newUnique' #-}
src/Polysemy/IdempotentLowering.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE ImpredicativeTypes #-}-+-- | =__Unless you absolutely have to use explicit lowering functions, use "Polysemy.Final" instead__ module Polysemy.IdempotentLowering   ( (.@!)   , nat
+ src/Polysemy/Reader/More.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE RecursiveDo #-}+module Polysemy.Reader.More+  (+    module Polysemy.Reader+    -- * Interpretations+  , runReaderFixSem+  ) where++import Polysemy+import Polysemy.Reader+import Polysemy.Fixpoint++------------------------------------------------------------------------------+-- | Runs a 'Reader' effect by running a monadic action /once/, after the+-- 'Sem' has completed, and then providing the result to each request+-- recursively.+runReaderFixSem :: forall i r a+                 . Member Fixpoint r+                => Sem r i+                -> Sem (Reader i ': r) a+                -> Sem r a+runReaderFixSem m sem = do+  rec+    a <- runReader i sem+    i <- m+  return a+{-# INLINE runReaderFixSem #-}
+ src/Polysemy/RevState.hs view
@@ -0,0 +1,154 @@+{-# LANGUAGE RecursiveDo, TemplateHaskell #-}+module Polysemy.RevState+ ( -- * Effect+   RevState (..)++   -- * Actions+ , revState+ , revGet+ , revPut+ , revModify++   -- * Interpretations+ , runRevState+ , runLazyRevState+ ) where++import Control.Monad.Fix++import Polysemy+import Polysemy.Fixpoint+import Polysemy.Internal+import Polysemy.Internal.Union++------------------------------------------------------------------------------+-- | A 'Polysemy.State.State' effect for threading state /backwards/ instead+-- of forwards through a computation.+newtype RevState s m a where+  RevState :: (s -> (s, a)) -> RevState s m a++makeSem_ ''RevState+++------------------------------------------------------------------------------+-- | Gets the state as sent from the next call to 'revState'+-- \/ 'revPut' \/ 'revModify', use it, and send a new state into the past.+revState :: forall s a r+          . Member (RevState s) r+         => (s -> (s, a))+         -> Sem r a++------------------------------------------------------------------------------+-- | Gets the state as sent from the next call to 'revState' \/ 'revPut'+-- \/ 'revModify'.+revGet :: forall s r+        . Member (RevState s) r+       => Sem r s+revGet = revState $ \s -> (s, s)++------------------------------------------------------------------------------+-- | Sends a new state into the past.+revPut :: forall s r+        . Member (RevState s) r+       => Sem r s+revPut = revState $ \s -> (s, s)++------------------------------------------------------------------------------+-- | Gets the state as sent from the next call to 'revState'+-- \/ 'revModify' \/ 'revPut', modify it, and return it into the past.+revModify :: forall s r+           . Member (RevState s) r+          => (s -> s)+          -> Sem r ()+revModify f = revState $ \s -> (f s, ())+++------------------------------------------------------------------------------+-- | Run a 'RevState' effect with local state that is propagated /backwards/+-- through the computation, from last action to first.+runRevState :: Member Fixpoint r+            => s+            -> Sem (RevState s ': r) a+            -> Sem r (s, a)+runRevState s =+   (`runRevStateT` s)+  . runRevStateInC++------------------------------------------------------------------------------+-- | Run a 'RevState' effect with local state that is lazily propagated+-- /backwards/ through the computation, from last action to first.+runLazyRevState :: Member Fixpoint r+                => s+                -> Sem (RevState s ': r) a+                -> Sem r (s, a)+runLazyRevState s =+   (`runLazyRevStateT` s)+  . runLazyRevStateInC++newtype RevStateT s m a = RevStateT { runRevStateT :: s -> m (s, a) }+  deriving (Functor)++instance MonadFix m => Applicative (RevStateT s m) where+  pure a = RevStateT $ \s -> pure (s, a)+  ff <*> fa = RevStateT $ \s -> do+    rec+      (s'', f) <- runRevStateT ff s'+      (s',  a) <- runRevStateT fa s+    return (s'', f a)+  fa *> fb = fa >>= \_ -> fb++instance MonadFix m => Monad (RevStateT s m) where+  m >>= f = RevStateT $ \s -> do+    rec+      (s'', a) <- runRevStateT m s'+      (s',  b) <- runRevStateT (f a) s+    return (s'', b)++newtype LazyRevStateT s m a = LazyRevStateT { runLazyRevStateT :: s -> m (s, a) }+  deriving (Functor)++instance MonadFix m => Applicative (LazyRevStateT s m) where+  pure a = LazyRevStateT $ \s -> pure (s, a)+  ff <*> fa = LazyRevStateT $ \s -> do+    rec+      ~(s'', f) <- runLazyRevStateT ff s'+      ~(s',  a) <- runLazyRevStateT fa s+    return (s'', f a)+  fa *> fb = fa >>= \_ -> fb++instance MonadFix m => Monad (LazyRevStateT s m) where+  m >>= f = LazyRevStateT $ \s -> do+    rec+      ~(s'', a) <- runLazyRevStateT m s'+      ~(s',  b) <- runLazyRevStateT (f a) s+    return (s'', b)++runRevStateInC :: Member Fixpoint r+               => Sem (RevState s ': r) a+               -> RevStateT s (Sem r) a+runRevStateInC = usingSem $ \u -> RevStateT $ \s ->+  case decomp u of+    Right (Weaving (RevState f) st _ ex _) ->+      return $ (ex . (<$ st)) <$> f s+    Left g ->+      liftSem $+        weave+          (s, ())+          (uncurry runRevState)+          (Just . snd)+          g++runLazyRevStateInC :: Member Fixpoint r+                   => Sem (RevState s ': r) a+                   -> LazyRevStateT s (Sem r) a+runLazyRevStateInC = usingSem $ \u -> LazyRevStateT $ \s ->+  case decomp u of+    Right (Weaving (RevState f) st _ ex _) ->+      return $ (ex . (<$ st)) <$> f s+    Left g ->+      liftSem $+        weave+          (s, ())+          (uncurry runLazyRevState)+          (Just . snd)+          g
src/Polysemy/Shift.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE Trustworthy #-} module Polysemy.Shift   (     module Polysemy.Cont@@ -16,7 +16,7 @@     -- * Interpretations   , runShiftPure   , runShiftM-  , runShiftFinal+  , shiftToFinal   , runShiftWithCPure   , runShiftWithCM @@ -75,7 +75,7 @@ -- The final return type is wrapped in a 'Maybe' due to the fact that -- any continuation may fail locally. ----- This is a safe variant of 'runContUnsafe', as this may only be used+-- This is a safe variant of 'runShiftUnsafe', as this may only be used -- as the final interpreter before 'run'. runShiftPure :: Sem '[Shift (Ref (Sem '[]) (Maybe a)) a] a              -> Sem '[] (Maybe a)@@ -89,8 +89,8 @@ -- The final return type is wrapped in a 'Maybe' due to the fact that -- any continuation may fail locally. ----- This is a safe variant of 'runContUnsafe', as this may only be used--- as the final interpreter before 'run'.+-- This is a safe variant of 'runShiftUnsafe', as this may only be used+-- as the final interpreter before 'runM'. runShiftM :: Sem '[Shift (Ref (Sem '[Embed m]) (Maybe a)) a, Embed m] a           -> Sem '[Embed m] (Maybe a) runShiftM = runShiftUnsafe@@ -101,12 +101,12 @@ -- -- /Beware/: Effects that aren't interpreted in terms of the final monad -- will have local state semantics in regards to 'Shift' effects--- interpreted this way. See 'interpretFinal'.-runShiftFinal :: forall s m a r+-- interpreted this way. See 'Final'.+shiftToFinal :: forall s m a r               .  (Member (Final (ContT (Maybe s) m)) r, Monad m)               => Sem (Shift (Ref m (Maybe s)) s ': r) a               -> Sem r a-runShiftFinal = interpretFinal $ \case+shiftToFinal = interpretFinal $ \case   Trap main -> do     main'         <- bindS main     s             <- getInitialStateS@@ -125,7 +125,7 @@     Inspector ins <- getInspectorS     liftS $ ContT $ \c ->       runContT main' (pure . ins) >>= c-{-# INLINE runShiftFinal #-}+{-# INLINE shiftToFinal #-}  ----------------------------------------------------------------------------- -- | Runs a 'Shift' effect by explicitly providing a final@@ -238,8 +238,8 @@ -- 'Polysemy.Writer.censor' will be no-ops, 'Polysemy.Error.catch' will fail -- to catch exceptions, and 'Polysemy.Writer.listen' will always return 'mempty'. ----- __You should therefore use 'runShift' /after/ running all interpreters for--- your higher-order effects.__+-- __You should therefore use 'runShiftUnsafe' /after/ running all__+-- __interpreters for your higher-order effects.__ runShiftUnsafe :: Sem (Shift (Ref (Sem r) (Maybe a)) a ': r) a -> Sem r (Maybe a) runShiftUnsafe = runShiftWithCUnsafe (pure . Just) {-# INLINE runShiftUnsafe #-}@@ -255,8 +255,8 @@ -- 'Polysemy.Writer.censor' will be no-ops, 'Polysemy.Error.catch' will fail -- to catch exceptions, and 'Polysemy.Writer.listen' will always return 'mempty'. ----- __You should therefore use 'runShiftWithC' /after/ running all interpreters for--- your higher-order effects.__+-- __You should therefore use 'runShiftWithCUnsafe' /after/ running all__+-- __interpreters for your higher-order effects.__ runShiftWithCUnsafe :: forall s a r.                        (a -> Sem r (Maybe s))                     -> Sem (Shift (Ref (Sem r) (Maybe s)) s ': r) a@@ -278,8 +278,8 @@ -- 'Polysemy.Writer.censor' will be no-ops, 'Polysemy.Error.catch' will fail -- to catch exceptions, and 'Polysemy.Writer.listen' will always return 'mempty'. ----- __You should therefore use 'runShift' /after/ running all interpreters for--- your higher-order effects.__+-- __You should therefore use 'runContShiftUnsafe' /after/ running all__+-- __interpreters for your higher-order effects.__ runContShiftUnsafe :: Sem (   Cont (Ref (Sem r) (Maybe a))                            ': Shift (Ref (Sem r) (Maybe a)) a                            ': r) a@@ -299,8 +299,8 @@ -- 'Polysemy.Writer.censor' will be no-ops, 'Polysemy.Error.catch' will fail -- to catch exceptions, and 'Polysemy.Writer.listen' will always return 'mempty'. ----- __You should therefore use 'runShift' /after/ running all interpreters for--- your higher-order effects.__+-- __You should therefore use 'runContShiftWithCUnsafe' /after/ running all__+-- __interpreters for your higher-order effects.__ runContShiftWithCUnsafe :: forall s a r.                            (a -> Sem r (Maybe s))                         -> Sem (   Cont (Ref (Sem r) (Maybe s))
+ src/Polysemy/Tagged.hs view
@@ -0,0 +1,77 @@+module Polysemy.Tagged+  (+    -- * Effect+    Tagged (..)++    -- * Actions+  , tag++    -- * Interpretations+  , untag+  , retag+  ) where++import Polysemy+import Polysemy.Internal+import Polysemy.Internal.Union+++------------------------------------------------------------------------------+-- | An effect for annotating effects and disambiguating identical effects.+newtype Tagged k e m a where+  Tagged :: forall k e m a. e m a -> Tagged k e m a++------------------------------------------------------------------------------+-- | Tag uses of an effect, effectively gaining access to the+-- tagged effect locally.+--+-- This may be used to create @tagged-@ variants of regular actions.+--+-- For example (the type applications aren't needed when using @polysemy-plugin@):+--+-- @+-- taggedLocal :: forall k i r a+--              . 'Member' ('Tagged' k ('Polysemy.Reader.Reader' i)) r+--             => (i -> i)+--             -> 'Sem' r a+--             -> 'Sem' r a+-- taggedLocal f m =+--   'tag' @k @('Polysemy.Reader.Reader' i) $ 'Polysemy.Reader.local' @i f ('raise' m)+-- @+--+tag :: forall k e r a+     . Member (Tagged k e) r+    => Sem (e ': r) a+    -> Sem r a+tag = hoistSem $ \u -> case decomp u of+  Right (Weaving e s wv ex ins) ->+    injWeaving $ Weaving (Tagged e) s (tag . wv) ex ins+  Left g -> hoist tag g+{-# INLINE tag #-}++------------------------------------------------------------------------------+-- | Run a @'Tagged' k e@ effect through reinterpreting it to @e@+untag :: forall k e r a+       . Sem (Tagged k e ': r) a+      -> Sem (e ': r) a+-- TODO(KingoftheHomeless): I think this is safe to replace with 'unsafeCoerce',+-- but doing so probably worsens performance, as it hampers optimizations.+-- Once GHC 8.10 rolls out, I will benchmark and compare.+untag = hoistSem $ \u -> case decompCoerce u of+  Right (Weaving (Tagged e) s wv ex ins) ->+    Union SZ (Weaving e s (untag . wv) ex ins)+  Left g -> hoist untag g+{-# INLINE untag #-}++------------------------------------------------------------------------------+-- | Transform a @'Tagged' k1 e@ effect into a @'Tagged' k2 e@ effect+retag :: forall k1 k2 e r a+       . Member (Tagged k2 e) r+      => Sem (Tagged k1 e ': r) a+      -> Sem r a+retag = hoistSem $ \u -> case decomp u of+  Right (Weaving (Tagged e) s wv ex ins) ->+    injWeaving $ Weaving (Tagged e) s (retag . wv) ex ins+  Left g -> hoist retag g+{-# INLINE retag #-}+
test/ContSpec.hs view
@@ -68,7 +68,7 @@     (`S.runState` 1)   . runM   . runContM-  . runStateFinal+  . stateToEmbed   $ stateTest  test5 :: IO (Int, Int)@@ -95,7 +95,7 @@   . runFinal   . runTraceList   . runReader ""-  . runContFinal+  . contToFinal   $ do   j <- local (++".") $ callCC $ \c -> do     j <- ask@@ -113,8 +113,8 @@      ($ 1)    . (`C.runContT` pure)    . runFinal-   . runReaderFinal-   . runContFinal+   . readerToFinal+   . contToFinal    $ do   callCC $ \c ->     local (+1) (c ())@@ -134,14 +134,14 @@       test3 `shouldBe` Right ()    describe "runContM" $ do-    it "should have global state semantics with runStateFinal" $+    it "should have global state semantics with stateToEmbed" $       test4 `shouldBe` (3, 3) -    it "should have global state semantics with runStateInIORef" $ do+    it "should have global state semantics with runStateIORef" $ do       r <- test5       r `shouldBe` (3, 3) -  describe "runContFinal" $ do+  describe "contToFinal" $ do     it "should work just like runContPure/M." $       test7 `shouldBe` (["Nothing", "at", "all."], ".") 
test/FinalSpec.hs view
@@ -8,83 +8,18 @@ import Control.Monad.Writer hiding (MonadWriter(..), censor)  import Data.Either-import Data.IORef  import Polysemy -import Polysemy.Trace-import Polysemy.State--import Polysemy.Final.Async-import Polysemy.Final.Fixpoint-import Polysemy.Final.Error-+import Polysemy.Error import Polysemy.Reader import Polysemy.Writer+import Polysemy.State+import Polysemy.Trace import Polysemy.Final.MTL -data Node a = Node a (IORef (Node a))--mkNode :: (Member (Embed IO) r, Member Fixpoint r)-       => a-       -> Sem r (Node a)-mkNode a = mdo-  let nd = Node a p-  p <- embed $ newIORef nd-  return nd--linkNode :: Member (Embed IO) r-         => Node a-         -> Node a-         -> Sem r ()-linkNode (Node _ r) b =-  embed $ writeIORef r b--readNode :: Node a -> a-readNode (Node a _) = a--follow :: Member (Embed IO) r-       => Node a-       -> Sem r (Node a)-follow (Node _ ref) = embed $ readIORef ref--test1 :: IO (Either Int (String, Int, Maybe Int))-test1 = do-  ref <- newIORef "abra"-  runFinal-    . runStateIORef ref -- Order of these interpreters don't matter-    . runErrorInIOFinal-    . runFixpointFinal-    . runAsyncFinal-     $ do-     n1 <- mkNode 1-     n2 <- mkNode 2-     linkNode n2 n1-     aw <- async $ do-       linkNode n1 n2-       modify (++"hadabra")-       n2' <- follow n2-       throw (readNode n2')-     m <- await aw `catch` (\s -> return $ Just s)-     n1' <- follow n1-     s <- get-     return (s, readNode n1', m)--test2 :: IO ([String], Either () ())-test2 =-    runFinal-  . runTraceList-  . runErrorInIOFinal-  . runAsyncFinal-  $ do-  fut <- async $ do-    trace "Global state semantics?"-  catch (trace "What's that?" *> throw ()) (\_ -> return ())-  _ <- await fut-  trace "Nothing at all."--test3 :: Int -> (Either Bool (([String], Int), Int), [Int])-test3 i =+test1 :: Int -> (Either Bool (([String], Int), Int), [Int])+test1 i =   let     g = do       j  <- ask@@ -101,11 +36,12 @@   . runExceptT   . (`runStateT` 0)   . runFinal+  . embedToFinal   . runTraceList -- Order of these interpreters don't matter-  . runWriterFinal-  . runStateFinal-  . runErrorFinal-  . runReaderFinal+  . writerToFinal+  . stateToEmbed+  . errorToFinal+  . readerToFinal   $ do     ask >>= put     res <-@@ -119,25 +55,9 @@  spec :: Spec spec = do-  describe "Final on IO" $ do-    it "should terminate successfully, with no exceptions,\-        \ and have global state semantics on State." $ do-      res1 <- test1-      res1 `shouldSatisfy` isRight-      case res1 of-        Right (s, i, j) -> do-          i `shouldBe` 2-          j `shouldBe` Just 1-          s `shouldBe` "abrahadabra"-        _ -> pure ()--    it "should treat trace with local state semantics" $ do-      res2 <- test2-      res2 `shouldBe` (["Nothing at all."], Right ())-   describe "Final with MTL" $ do     it "should all work without issue" $ do-      let (r, written) = test3 0+      let (r, written) = test1 0       written `shouldBe` [1,0,777,7]       r `shouldSatisfy` isRight       case r of@@ -148,12 +68,12 @@         _ -> pure ()      it "should fail, dropping trace, state, and censoring" $ do-      let (r, written) = test3 1+      let (r, written) = test1 1       r `shouldBe` Left True       written `shouldBe` [2, 1]      it "should catch exception, locally dropping trace and state, and not censor" $ do-      let (r, written) = test3 2+      let (r, written) = test1 2       written `shouldBe` [3,2,2]       r `shouldSatisfy` isRight       case r of
test/IdempotentLoweringSpec.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE ImpredicativeTypes #-}-+{-# OPTIONS_GHC -Wno-deprecations #-} module IdempotentLoweringSpec where  import Data.IORef
+ test/RevStateSpec.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE RecursiveDo #-}+module RevStateSpec where++import Test.Hspec++import Data.Functor.Identity++import Polysemy+import Polysemy.State+import Polysemy.RevState+import Polysemy.EndState+import Polysemy.Fixpoint++runStateCircular :: (Member (State s) r, Member Fixpoint r)+                 => Sem (RevState s ': r) a+                 -> Sem r (s, a)+runStateCircular sem = runEndState $ do+  s <- getEndState+  raise $ runRevState s sem++test :: String+test =+    fst+  . snd+  . runIdentity+  . runFinal+  . fixpointToFinal+  . runState ""+  . runStateCircular+  $ do+   modify (++"time ")+   revModify (++"circle")+   modify (++"is ")+   revModify (++"flat ")+   modify (++"a ")++spec :: Spec+spec = do+  describe "runRevState" $ do+    it "should thread state backwards \+       \and work together with EndState" $+      test `shouldBe` "time is a flat circle"
test/ShiftSpec.hs view
@@ -72,9 +72,10 @@   . (`runStateT` 1)   . (`runContT` (pure . Just))   . runFinal-  . runStateFinal-  . runShiftFinal-  . runReaderFinal+  . embedToFinal+  . stateToEmbed+  . shiftToFinal+  . readerToFinal   $ do   shift $ \c -> do     _ <- local (+1) (c ())@@ -111,11 +112,11 @@       test3 `shouldBe` Just (Right ())    describe "runShiftM" $ do-    it "should modify multiple times with runStateInIORef" $ do+    it "should modify multiple times with runStateIORef" $ do       res <- test4       res `shouldBe` Just 4 -  describe "runShiftFinal" $ do+  describe "shiftToFinal" $ do     it "should modify multiple times with runStateFinal\         \ and should be able to apply local to continuation" $       test5 `shouldBe` (Just 10, 10)