polysemy-zoo 0.6.0.1 → 0.7.0.0
raw patch · 11 files changed
+338/−185 lines, 11 filesdep +compactdep +exceptionsdep +streamingdep −binarydep −bytestringdep −hedisdep ~polysemydep ~polysemy-pluginnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependencies added: compact, exceptions, streaming, text
Dependencies removed: binary, bytestring, hedis
Dependency ranges changed: polysemy, polysemy-plugin
API changes (from Hackage documentation)
- Polysemy.Alias: type InterpreterOf e r = forall x. Sem (e : r) x -> Sem r x
- Polysemy.KVStore: runKVStoreInRedis :: (Member (Embed Redis) r, Member (Error Reply) r, Binary k, Binary v) => (k -> ByteString) -> Sem (KVStore k v : r) a -> Sem r a
- Polysemy.Redis.Utils: Path :: ByteString -> Path
- Polysemy.Redis.Utils: [getPath] :: Path -> ByteString
- Polysemy.Redis.Utils: getFromRedis :: Binary a => ByteString -> a
- Polysemy.Redis.Utils: instance Data.String.IsString Polysemy.Redis.Utils.Path
- Polysemy.Redis.Utils: instance GHC.Classes.Eq Polysemy.Redis.Utils.Path
- Polysemy.Redis.Utils: instance GHC.Classes.Ord Polysemy.Redis.Utils.Path
- Polysemy.Redis.Utils: instance GHC.Show.Show Polysemy.Redis.Utils.Path
- Polysemy.Redis.Utils: newtype Path
- Polysemy.Redis.Utils: putForRedis :: Binary a => a -> ByteString
- Polysemy.SetStore: runSetStoreInRedis :: (Member (Embed Redis) r, Member (Error Reply) r, Binary k, Binary v) => (k -> Path) -> InterpreterOf (SetStore k v) r
- 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.ConstraintAbsorber.MonadCatch: absorbMonadCatch :: Member (Error SomeException) r => (MonadCatch (Sem r) => Sem r a) -> Sem r a
+ Polysemy.ConstraintAbsorber.MonadCatch: absorbMonadThrow :: Member (Error SomeException) r => (MonadThrow (Sem r) => Sem r a) -> Sem r a
+ Polysemy.ConstraintAbsorber.MonadCatch: class (Typeable e, Show e) => Exception e
+ Polysemy.ConstraintAbsorber.MonadCatch: data SomeException
+ Polysemy.ConstraintAbsorber.MonadCatch: displayException :: Exception e => e -> String
+ Polysemy.ConstraintAbsorber.MonadCatch: fromException :: Exception e => SomeException -> Maybe e
+ Polysemy.ConstraintAbsorber.MonadCatch: instance forall (m :: * -> *) k (s' :: k). GHC.Base.Applicative m => GHC.Base.Applicative (Polysemy.ConstraintAbsorber.MonadCatch.Action m s')
+ Polysemy.ConstraintAbsorber.MonadCatch: instance forall (m :: * -> *) k (s' :: k). GHC.Base.Functor m => GHC.Base.Functor (Polysemy.ConstraintAbsorber.MonadCatch.Action m s')
+ Polysemy.ConstraintAbsorber.MonadCatch: instance forall (m :: * -> *) k (s' :: k). GHC.Base.Monad m => GHC.Base.Monad (Polysemy.ConstraintAbsorber.MonadCatch.Action m s')
+ Polysemy.ConstraintAbsorber.MonadCatch: instance forall k (m :: * -> *) (s' :: k). (GHC.Base.Monad m, Data.Reflection.Reifies s' (Polysemy.ConstraintAbsorber.MonadCatch.CatchDict m)) => Control.Monad.Catch.MonadCatch (Polysemy.ConstraintAbsorber.MonadCatch.Action m s')
+ Polysemy.ConstraintAbsorber.MonadCatch: instance forall k (m :: * -> *) (s' :: k). (GHC.Base.Monad m, Data.Reflection.Reifies s' (Polysemy.ConstraintAbsorber.MonadCatch.CatchDict m)) => Control.Monad.Catch.MonadThrow (Polysemy.ConstraintAbsorber.MonadCatch.Action m s')
+ Polysemy.ConstraintAbsorber.MonadCatch: runMonadCatch :: Exception e => (Maybe e -> e') -> Sem (Error SomeException : (Error e' : r)) a -> Sem r (Either e' a)
+ Polysemy.ConstraintAbsorber.MonadCatch: runMonadCatchAsText :: Sem (Error SomeException : (Error Text : r)) a -> Sem r (Either Text a)
+ Polysemy.ConstraintAbsorber.MonadCatch: toException :: Exception e => e -> SomeException
+ Polysemy.Input.Streaming: exhaust :: Member (Input i) r => Stream (Of i) (Sem r) a
+ Polysemy.Input.Streaming: runInputViaInfiniteStream :: forall i r. Stream (Of i) (Sem r) Void -> InterpreterFor (Input i) r
+ Polysemy.Input.Streaming: runInputViaStream :: Stream (Of i) (Sem r) () -> InterpreterFor (Input (Maybe i)) r
+ Polysemy.Input.Streaming: yieldInput :: Member (Input i) r => Stream (Of i) (Sem r) ()
+ Polysemy.Input.Streaming: yieldRace :: Members '[Final IO, Input i1, Input i2] r => Stream (Of (Either i1 i2)) (Sem r) ()
+ Polysemy.Reader.Compact: runReaderWithCompacted :: forall r i a. Member (Embed IO) r => i -> Sem (Reader i : r) a -> Sem r a
+ Polysemy.Reader.Compact: runReaderWithExistingCompacted :: forall r i a. Member (Embed IO) r => Compact i -> Sem (Reader i : r) a -> Sem r a
- Polysemy.EndState: getEndState :: forall s_aBgI r_aBhB. MemberWithError (EndState s_aBgI) r_aBhB => Sem r_aBhB s_aBgI
+ Polysemy.EndState: getEndState :: forall s_aA6w r_aA7p. MemberWithError (EndState s_aA6w) r_aA7p => Sem r_aA7p s_aA6w
- Polysemy.Floodgate: hold :: forall r_apIf. MemberWithError Floodgate r_apIf => Sem r_apIf () -> Sem r_apIf ()
+ Polysemy.Floodgate: hold :: forall r_aoMw. MemberWithError Floodgate r_aoMw => Sem r_aoMw () -> Sem r_aoMw ()
- Polysemy.Floodgate: release :: forall r_apIh. MemberWithError Floodgate r_apIh => Sem r_apIh ()
+ Polysemy.Floodgate: release :: forall r_aoMy. MemberWithError Floodgate r_aoMy => Sem r_aoMy ()
- Polysemy.Fresh: fresh :: forall uniq_av8A r_av9t. MemberWithError (Fresh uniq_av8A) r_av9t => Sem r_av9t uniq_av8A
+ Polysemy.Fresh: fresh :: forall uniq_augT r_auhM. MemberWithError (Fresh uniq_augT) r_auhM => Sem r_auhM uniq_augT
- 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: lookupKV :: forall k_ayqZ v_ayr0 r_aysT. MemberWithError (KVStore k_ayqZ v_ayr0) r_aysT => k_ayqZ -> Sem r_aysT (Maybe v_ayr0)
- 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.KVStore: updateKV :: forall k_ayr2 v_ayr3 r_aysV. MemberWithError (KVStore k_ayr2 v_ayr3) r_aysV => k_ayr2 -> Maybe v_ayr3 -> Sem r_aysV ()
- Polysemy.Random: random :: forall r_aAsA x_aAqQ. (MemberWithError Random r_aAsA, Random x_aAqQ) => Sem r_aAsA x_aAqQ
+ Polysemy.Random: random :: forall r_azvr x_aztH. (MemberWithError Random r_azvr, Random x_aztH) => Sem r_azvr x_aztH
- 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.Random: randomR :: forall r_azvs x_aztJ. (MemberWithError Random r_azvs, Random x_aztJ) => (x_aztJ, x_aztJ) -> Sem r_azvs x_aztJ
- Polysemy.SetStore: addS :: forall k_aJU6 v_aJU7 r_aJX2. MemberWithError (SetStore k_aJU6 v_aJU7) r_aJX2 => k_aJU6 -> v_aJU7 -> Sem r_aJX2 ()
+ Polysemy.SetStore: addS :: forall k_aByo v_aByp r_aBBk. MemberWithError (SetStore k_aByo v_aByp) r_aBBk => k_aByo -> v_aByp -> Sem r_aBBk ()
- Polysemy.SetStore: delS :: forall k_aJU9 v_aJUa r_aJX5. MemberWithError (SetStore k_aJU9 v_aJUa) r_aJX5 => k_aJU9 -> v_aJUa -> Sem r_aJX5 ()
+ Polysemy.SetStore: delS :: forall k_aByr v_aBys r_aBBn. MemberWithError (SetStore k_aByr v_aBys) r_aBBn => k_aByr -> v_aBys -> Sem r_aBBn ()
- Polysemy.SetStore: memberS :: forall k_aJUc v_aJUd r_aJX8. MemberWithError (SetStore k_aJUc v_aJUd) r_aJX8 => k_aJUc -> v_aJUd -> Sem r_aJX8 Bool
+ Polysemy.SetStore: memberS :: forall k_aByu v_aByv r_aBBq. MemberWithError (SetStore k_aByu v_aByv) r_aBBq => k_aByu -> v_aByv -> Sem r_aBBq Bool
- Polysemy.SetStore: runSetStoreAsKVStore :: (Member (KVStore k (Set v)) r, Ord v) => InterpreterOf (SetStore k v) r
+ Polysemy.SetStore: runSetStoreAsKVStore :: (Member (KVStore k (Set v)) r, Ord v) => Sem (SetStore k v : r) x -> Sem r x
Files
- ChangeLog.md +18/−0
- polysemy-zoo.cabal +14/−12
- src/Polysemy/Alias.hs +0/−6
- src/Polysemy/ConstraintAbsorber/MonadCatch.hs +125/−0
- src/Polysemy/Input/Streaming.hs +86/−0
- src/Polysemy/KVStore.hs +0/−33
- src/Polysemy/Reader/Compact.hs +37/−0
- src/Polysemy/Redis/Utils.hs +0/−24
- src/Polysemy/SetStore.hs +1/−32
- src/Polysemy/Tagged.hs +0/−77
- test/ConstraintAbsorberSpec.hs +57/−1
ChangeLog.md view
@@ -1,5 +1,23 @@ # Changelog for polysemy-zoo +## 0.7.0.0 (2020-02-14)+### Breaking Changes+- `Tagged` has been migrated to `polysemy` proper.+- `Polysemy.Alias` and `InterpreterOf` has been removed in favor of+ `InterpreterFor`, which is now part of `polysemy` proper+ (thanks to @bolt12).+- Removed `runKVStoreInRedis`, `runSetStoreInRedis`, and `Polysemy.Redis.Utils`+ due to lack of use.++### Other Changes+- Added `MonadThrow` and `MonadCatch` constraint absorbers which operate+ via `Error SomeException` (thanks to @adamConnerSax).+- Added `Polysemy.Input.Streaming`, which offers+ [streaming](https://hackage.haskell.org/package/streaming) interoperability.+- Added `Polysemy.Reader.Compact`, which is useful for `Reader` effects+ which provide a large structure (thanks to @spacekitteh).++ ## 0.6.0.1 (2019-09-12) - Fixed the implementation of `atomicPut`
polysemy-zoo.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 508b2d70f45ca899d68cc756e99c4a93128f7748848feefea756030db96c9c94+-- hash: 3ca3f0fd7140b4210529e77e057687ebd67bb4477155611458e964afa5cdc192 name: polysemy-zoo-version: 0.6.0.1+version: 0.7.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@@ -29,9 +29,9 @@ library exposed-modules:- Polysemy.Alias Polysemy.Capture Polysemy.ConstraintAbsorber+ Polysemy.ConstraintAbsorber.MonadCatch Polysemy.ConstraintAbsorber.MonadCont Polysemy.ConstraintAbsorber.MonadError Polysemy.ConstraintAbsorber.MonadReader@@ -48,17 +48,17 @@ Polysemy.Floodgate Polysemy.Fresh Polysemy.IdempotentLowering+ Polysemy.Input.Streaming Polysemy.KVStore Polysemy.Operators Polysemy.Random+ Polysemy.Reader.Compact 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:@@ -68,18 +68,19 @@ build-depends: async >=2.2 && <3 , base >=4.9 && <5- , binary >=0.8.5.1 && <0.9- , bytestring >=0.10.8.2 && <0.11+ , compact >=0.1.0.1 , constraints >=0.10.1 && <0.12 , containers >=0.5 && <0.7 , contravariant <2+ , exceptions >=0.10.0 && <0.11 , ghc-prim >=0.5.2 && <0.6- , hedis >=0.10 && <0.13 , mtl >=2.0.1.0 && <3.0.0.0- , polysemy >=1.2.0.0+ , polysemy >=1.2.1.0 , polysemy-plugin >=0.2 , random >=1.1 && <1.2 , reflection >=2.1.4 && <3.0.0+ , streaming+ , text >=1.1.0 && <1.3 , transformers >=0.5.2.0 && <0.6 default-language: Haskell2010 @@ -107,13 +108,12 @@ build-depends: async >=2.2 && <3 , base >=4.9 && <5- , binary >=0.8.5.1 && <0.9- , bytestring >=0.10.8.2 && <0.11+ , compact >=0.1.0.1 , constraints >=0.10.1 && <0.12 , containers >=0.5 && <0.7 , contravariant <2+ , exceptions >=0.10.0 && <0.11 , 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 >=1.2.0.0@@ -121,5 +121,7 @@ , polysemy-zoo , random >=1.1 && <1.2 , reflection >=2.1.4 && <3.0.0+ , streaming+ , text >=1.1.0 && <1.3 , transformers >=0.5.2.0 && <0.6 default-language: Haskell2010
− src/Polysemy/Alias.hs
@@ -1,6 +0,0 @@-module Polysemy.Alias where--import Polysemy--type InterpreterOf e r = forall x. Sem (e ': r) x -> Sem r x-
+ src/Polysemy/ConstraintAbsorber/MonadCatch.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}++module Polysemy.ConstraintAbsorber.MonadCatch+ (+ -- * Constraint Absorbers+ absorbMonadThrow+ , absorbMonadCatch+ -- * run helper+ , runMonadCatch+ , runMonadCatchAsText+ -- * Re-exports+ , Exception(..)+ , SomeException+ )+where++import qualified Control.Monad.Catch as C+import Control.Monad.Catch ( Exception(..)+ , SomeException+ , toException+ )++import qualified Data.Text as T+import Polysemy+import Polysemy.ConstraintAbsorber+import qualified Polysemy.Error as E+++------------------------------------------------------------------------------+-- | Like 'E.runError' but applies a given function from 'SomeException'+-- to some other type, typically something less opaque.+-- e.g.:+-- @runErrorForMonadCatch C.displayException@+-- +-- @since 0.7.0.0+runMonadCatch+ :: Exception e+ => (Maybe e -> e')+ -> Sem (E.Error C.SomeException : E.Error e' : r) a+ -> Sem r (Either e' a)+runMonadCatch f = E.runError . E.mapError (f . C.fromException)++runMonadCatchAsText+ :: Sem (E.Error C.SomeException : E.Error T.Text : r) a+ -> Sem r (Either T.Text a)+runMonadCatchAsText = E.runError . E.mapError (T.pack . C.displayException)++++-- | Introduce a local 'S.MonadCatch' constraint on 'Sem' --- allowing it to+-- interop nicely with exceptions+--+-- @since 0.7.0.0+absorbMonadCatch+ :: Member (E.Error C.SomeException) r+ => (C.MonadCatch (Sem r) => Sem r a)+ -- ^ A computation that requires an instance of 'C.MonadCatch'+ -- or 'C.MonadThrow' for+ -- 'Sem'. This might be something with type @'C.MonadCatch' e m => m a@.+ -> Sem r a+absorbMonadCatch =+ absorbWithSem @C.MonadCatch @Action (CatchDict E.throw E.catch) (Sub Dict)+{-# INLINABLE absorbMonadCatch #-}++-- | Introduce a local 'S.MonadThrow' constraint on 'Sem' --- allowing it to+-- interop nicely with exceptions+--+-- @since 0.7.0.0+absorbMonadThrow+ :: Member (E.Error C.SomeException) r+ => (C.MonadThrow (Sem r) => Sem r a)+ -- ^ A computation that requires an instance of 'C.MonadCatch'+ -- or 'C.MonadThrow' for+ -- 'Sem'. This might be something with type @'C.MonadCatch' e m => m a@.+ -> Sem r a+absorbMonadThrow = absorbMonadCatch+{-# INLINABLE absorbMonadThrow #-}++------------------------------------------------------------------------------+-- | A dictionary of the functions we need to supply+-- to make an instance of Error+data CatchDict m = CatchDict+ { throwM_ :: forall a. C.SomeException -> m a+ , catch_ :: forall a. m a -> (C.SomeException -> 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 { action :: m a }+ deriving (Functor, Applicative, Monad)+++------------------------------------------------------------------------------+-- | Given a reifiable mtl Error dictionary,+-- we can make an instance of @MonadError@ for the action+-- wrapped in @Action@.+instance ( Monad m+ , Reifies s' (CatchDict m)+ ) => C.MonadThrow (Action m s') where+ throwM e = Action $ throwM_ (reflect $ Proxy @s') (C.toException e)+ {-# INLINEABLE throwM #-}++instance ( Monad m+ , Reifies s' (CatchDict m)+ ) => C.MonadCatch (Action m s') where+ catch x f =+ let catchF = catch_ (reflect $ Proxy @s')+ in Action $ (action x) `catchF` \e -> case C.fromException e of+ Just e' -> action $ f e'+ _ -> throwM_ (reflect $ Proxy @s') (C.toException e)+ {-# INLINEABLE catch #-}++
+ src/Polysemy/Input/Streaming.hs view
@@ -0,0 +1,86 @@+module Polysemy.Input.Streaming+ ( -- * Underlying Effect+ module Polysemy.Input++ -- * Actions+ , yieldInput+ , yieldRace+ , exhaust++ -- * Intepretations+ , runInputViaStream+ , runInputViaInfiniteStream+ ) where++import qualified Control.Concurrent.Async as A+import Data.Functor.Of+import Data.Void+import Polysemy+import Polysemy.Final+import Polysemy.Input+import Polysemy.State+import qualified Streaming as S+import qualified Streaming.Prelude as S++++runInputViaStream+ :: S.Stream (Of i) (Sem r) ()+ -> InterpreterFor (Input (Maybe i)) r+runInputViaStream stream+ = evalState (Just stream)+ . reinterpret ( \Input ->+ get >>= \case+ Nothing -> pure Nothing+ Just s ->+ raise (S.inspect s) >>= \case+ Left () -> pure Nothing+ Right (i :> s') -> do+ put $ Just s'+ pure $ Just i+ )+++runInputViaInfiniteStream+ :: forall i r+ . S.Stream (Of i) (Sem r) Void+ -> InterpreterFor (Input i) r+runInputViaInfiniteStream stream+ = evalState stream+ . reinterpret ( \Input -> do+ s <- get+ raise (S.inspect s) >>= \case+ Left g -> absurd g+ Right (i :> s') -> do+ put s'+ pure i+ )+++yieldRace+ :: Members+ '[ Final IO+ , Input i1+ , Input i2+ ] r+ => S.Stream (S.Of (Either i1 i2)) (Sem r) ()+yieldRace = do+ z <- S.lift $ withStrategicToFinal $ do+ input1 <- runS input+ input2 <- runS input+ pure $ fmap sequenceEither $ A.race input1 input2+ S.yield z+++sequenceEither :: Functor f => Either (f a) (f b) -> f (Either a b)+sequenceEither (Left fa) = Left <$> fa+sequenceEither (Right fb) = Right <$> fb+++yieldInput :: Member (Input i) r => S.Stream (Of i) (Sem r) ()+yieldInput = S.lift input >>= S.yield+++exhaust :: Member (Input i) r => S.Stream (Of i) (Sem r) a+exhaust = S.repeatM input+
src/Polysemy/KVStore.hs view
@@ -16,18 +16,12 @@ -- * Interpretations , runKVStoreAsState , runKVStorePurely- , runKVStoreInRedis ) where -import Control.Monad-import Data.Binary (Binary)-import Data.ByteString (ByteString) import qualified Data.Map as M import Data.Maybe (isJust)-import qualified Database.Redis as R import Polysemy import Polysemy.Error-import Polysemy.Redis.Utils import Polysemy.State @@ -104,31 +98,4 @@ -> Sem r (M.Map k v, a) runKVStorePurely m = runState m . runKVStoreAsState {-# INLINE runKVStorePurely #-}---runKVStoreInRedis- :: ( Member (Embed R.Redis) r- , Member (Error R.Reply) r- , Binary k- , Binary v- )- => (k -> ByteString)- -> Sem (KVStore k v ': r) a- -> Sem r a-runKVStoreInRedis pf = interpret $ \case- LookupKV k -> do- res <- fromEitherM $ R.hget (pf k) $ putForRedis k- pure $ fmap getFromRedis res-- UpdateKV k Nothing ->- void . fromEitherM- . R.hdel (pf k)- . pure- $ putForRedis k-- UpdateKV k (Just v) ->- void . fromEitherM- . R.hset (pf k) (putForRedis k)- $ putForRedis v-{-# INLINE runKVStoreInRedis #-}
+ src/Polysemy/Reader/Compact.hs view
@@ -0,0 +1,37 @@+module Polysemy.Reader.Compact where++import Polysemy+import Polysemy.Reader++import Data.Compact++-----------------------------------------------------------------------------+-- | Run a 'Reader' effect by compacting a value; otherwise behaves as normal.+-- Useful for 'Reader' effects which provide a large structure.+runReaderWithCompacted+ :: forall r i a+ . Member (Embed IO) r+ => i+ -> Sem (Reader i ': r) a+ -> Sem r a+runReaderWithCompacted i sem = do+ compacted <- embed (compactWithSharing i)+ runReaderWithExistingCompacted compacted sem+{-# INLINE runReaderWithCompacted #-}++-----------------------------------------------------------------------------+-- | Run a 'Reader' effect with a value in a compact region. Will not add +-- 'local' values to the existing region, but will create a new region for it.+runReaderWithExistingCompacted+ :: forall r i a+ . Member (Embed IO) r+ => Compact i+ -> Sem (Reader i ': r) a+ -> Sem r a+runReaderWithExistingCompacted i = interpretH $ \case+ Ask -> pureT (getCompact i)+ Local f m -> do+ mm <- runT m+ let transformed = f (getCompact i)+ raise $ runReaderWithCompacted transformed mm+{-# INLINE runReaderWithExistingCompacted #-}
− src/Polysemy/Redis/Utils.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}--module Polysemy.Redis.Utils where--import Data.Binary (Binary)-import qualified Data.Binary as B-import Data.Binary.Get (runGet)-import Data.Binary.Put (runPut)-import Data.ByteString (ByteString)-import qualified Data.ByteString.Lazy.Char8 as L-import GHC.Exts---newtype Path = Path { getPath :: ByteString }- deriving (Eq, Ord, Show, IsString)---putForRedis :: Binary a => a -> ByteString-putForRedis = L.toStrict . runPut . B.put---getFromRedis :: Binary a => ByteString -> a-getFromRedis = runGet B.get . L.fromStrict-
src/Polysemy/SetStore.hs view
@@ -2,16 +2,10 @@ module Polysemy.SetStore where -import Control.Monad-import Data.Binary (Binary) import Data.Foldable import qualified Data.Set as S-import qualified Database.Redis as R import Polysemy-import Polysemy.Alias-import Polysemy.Error import Polysemy.KVStore-import Polysemy.Redis.Utils @@ -27,7 +21,7 @@ :: ( Member (KVStore k (S.Set v)) r , Ord v )- => InterpreterOf (SetStore k v) r+ => Sem (SetStore k v ': r) x -> Sem r x runSetStoreAsKVStore = interpret $ \case AddS k v -> lookupKV k >>= \case@@ -39,29 +33,4 @@ MemberS k v -> pure . maybe False (S.member v) =<< lookupKV k {-# INLINE runSetStoreAsKVStore #-}---runSetStoreInRedis- :: ( Member (Embed R.Redis) r- , Member (Error R.Reply) r- , Binary k- , Binary v- )- => (k -> Path)- -> InterpreterOf (SetStore k v) r-runSetStoreInRedis pf = interpret $ \case- AddS k v -> void- . fromEitherM- . R.sadd (getPath $ pf k)- . pure- $ putForRedis v- DelS k v -> void- . fromEitherM- . R.srem (getPath $ pf k)- . pure- $ putForRedis v- MemberS k v -> fromEitherM- . R.sismember (getPath $ pf k)- $ putForRedis v-{-# INLINE runSetStoreInRedis #-}
− src/Polysemy/Tagged.hs
@@ -1,77 +0,0 @@-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/ConstraintAbsorberSpec.hs view
@@ -1,6 +1,8 @@+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} + module ConstraintAbsorberSpec where import Polysemy@@ -13,14 +15,17 @@ import Polysemy.ConstraintAbsorber.MonadState import Polysemy.ConstraintAbsorber.MonadWriter import Polysemy.ConstraintAbsorber.MonadError+import Polysemy.ConstraintAbsorber.MonadCatch import Test.Hspec-import Control.Monad as M+import qualified Control.Monad as M+import Data.Maybe ( fromMaybe ) import qualified Control.Monad.Reader.Class as S import qualified Control.Monad.Writer.Class as S import qualified Control.Monad.State.Class as S import qualified Control.Monad.Error.Class as S+import qualified Control.Monad.Catch as S {-@@ -46,6 +51,23 @@ M.when (n == 0) $ S.throwError "Zero!" return n +data MyException = ZeroException | NegativeException | UnknownException deriving (Show, Eq)++instance S.Exception MyException++-- a different error handling option+throwOnZeroAndNegative :: S.MonadThrow m => Int -> m Int+throwOnZeroAndNegative n = do+ M.when (n == 0) $ S.throwM ZeroException+ M.when (n < 0) $ S.throwM NegativeException+ return n++-- this is dumb but it makes the point. +handleZero :: S.MonadThrow m => MyException -> m Int+handleZero ZeroException = return 0+handleZero e = S.throwM e++ someOfAll :: (S.MonadReader String m, S.MonadWriter [Int] m, S.MonadState Int m) => m String@@ -93,8 +115,42 @@ modify (\m -> m - (n `div` 2)) return () + it "should return (Right 1)." $ do+ flip shouldBe (Right 1) . run . runError $ absorbError $ throwOnZero 1 it "should return (Left \"Zero!\")." $ do flip shouldBe (Left "Zero!") . run . runError $ absorbError $ throwOnZero 0++ let toMyException = fromMaybe UnknownException+ it "should return (Right 1)." $ do+ flip shouldBe (Right 1)+ . run+ . runMonadCatch toMyException+ $ absorbMonadThrow+ $ throwOnZeroAndNegative 1+ it "should return (Left ZeroException)." $ do+ flip shouldBe (Left ZeroException)+ . run+ . runMonadCatch toMyException+ $ absorbMonadThrow+ $ throwOnZeroAndNegative 0+ it "should return (Left \"ZeroException\")." $ do+ flip shouldBe (Left "ZeroException")+ . run+ . runMonadCatchAsText+ $ absorbMonadThrow+ $ throwOnZeroAndNegative 0+ it "should return (Right 0)." $ do+ flip shouldBe (Right 0)+ . run+ . runMonadCatch toMyException+ $ absorbMonadCatch+ $ S.catch (throwOnZeroAndNegative 0) handleZero+ it "should return (Left NegativeException)." $ do+ flip shouldBe (Left NegativeException)+ . run+ . runMonadCatch toMyException+ $ absorbMonadCatch+ $ S.catch (throwOnZeroAndNegative (-1)) handleZero let runRWS :: String