packages feed

extensible-effects 1.8.0.0 → 1.8.1.0

raw patch · 19 files changed

+112/−71 lines, 19 filesdep +freedep +kan-extensionsPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: free, kan-extensions

API changes (from Hackage documentation)

- Control.Eff: E :: !(Union r (VE r w)) -> VE r w
- Control.Eff: Eff :: (forall w. (a -> VE r w) -> VE r w) -> Eff r a
- Control.Eff: Val :: w -> VE r w
- Control.Eff: data VE r w
- Control.Eff: instance Applicative (Eff r)
- Control.Eff: instance Functor (Eff r)
- Control.Eff: instance Monad (Eff r)
- Control.Eff: instance Typeable Eff
- Control.Eff: instance Typeable VE
- Control.Eff: newtype Eff r a
- Control.Eff: runEff :: Eff r a -> forall w. (a -> VE r w) -> VE r w
- Data.OpenUnion.Internal.OpenUnion1: Union :: (t v) -> Union r v
- Data.OpenUnion.Internal.OpenUnion1: class Member (t :: * -> *) r
- Data.OpenUnion.Internal.OpenUnion1: class Member t r => MemberU (tag :: k -> * -> *) (t :: * -> *) r | tag r -> t
- Data.OpenUnion.Internal.OpenUnion1: data (:>) (a :: * -> *) b
- Data.OpenUnion.Internal.OpenUnion1: data Union r v
- Data.OpenUnion.Internal.OpenUnion1: instance [overlap ok] Member t (t :> r)
- Data.OpenUnion.Internal.OpenUnion1: instance [overlap ok] Member t r => Member t (t' :> r)
- Data.OpenUnion.Internal.OpenUnion1: instance [overlap ok] MemberU tag (tag e) (tag e :> r)
- Data.OpenUnion.Internal.OpenUnion1: instance [overlap ok] MemberU tag t r => MemberU tag t (t' :> r)
+ Control.Eff: Free :: f (Free f a) -> Free a
+ Control.Eff: Pure :: a -> Free a
+ Control.Eff: data Free (f :: * -> *) a :: (* -> *) -> * -> *
+ Control.Eff: instance Typeable Codensity
+ Control.Eff: type Eff r = Codensity (VE r)
+ Control.Eff: type VE r = Free (Union r)
- Control.Eff: class Member (t :: * -> *) r
+ Control.Eff: class Member' t r ~ True => Member (t :: * -> *) r
- Data.OpenUnion: class Member (t :: * -> *) r
+ Data.OpenUnion: class Member' t r ~ True => Member (t :: * -> *) r

Files

README.md view
@@ -22,6 +22,8 @@     involving the type `t` would need to be added, which would defeat the point     of having the grouping in the first place. -  * Requires a `Typeable` instance on the return type.+  * Requires a `Typeable` instance on the return type. This is no longer a+    limitation on GHC versions 7.8 and above.   * Neither `Eff` nor `(:>)` has a `Typeable` instance, and can thus often not-    be used as a return type (e.g. `State` type) for other `Eff`s.+    be used as a return type (e.g. `State` type) for other `Eff`s. This is no+    longer a concern for GHC versions 7.8 and above.
extensible-effects.cabal view
@@ -6,7 +6,7 @@ -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             1.8.0.0+version:             1.8.1.0  -- A short (one-line) description of the package. synopsis:            An Alternative to Monad Transformers@@ -108,6 +108,8 @@    -- Other library packages from which modules are imported.   build-depends:       base >= 4.6 && < 5+                       , free >= 4.0 && < 5.0+                       , kan-extensions >= 4.0 && < 5.0                        -- For MonadIO instance                        , transformers >= 0.3 && < 0.5                        -- For MonadBase instance
src/Control/Eff.hs view
@@ -10,8 +10,13 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 708+-- needed for the orphan Typeable instance for Codensity below+{-# OPTIONS -fno-warn-orphans #-}+#endif  -- | Original work available at <http://okmij.org/ftp/Haskell/extensible/Eff.hs>. -- This module implements extensible effects as an alternative to monad transformers,@@ -63,8 +68,9 @@ -- > lastAndSum l = let (lst, (total, ())) = run $ runWriter $ runState 0 $ writeAndAdd l -- >                in (lst, total) module Control.Eff(-                    Eff (..)-                  , VE (..)+                    Eff+                  , VE+                  , Free (..)                   , Member                   , SetMember                   , Union@@ -81,8 +87,9 @@                   , unsafeReUnion                   ) where -import Control.Applicative (Applicative (..), (<$>))-import Control.Monad (ap)+import Control.Applicative ((<$>))+import Control.Monad.Codensity (Codensity (..))+import Control.Monad.Free (Free (..)) import Data.OpenUnion import Data.Typeable @@ -93,45 +100,49 @@ -- | A `VE` is either a value, or an effect of type @`Union` r@ producing another `VE`. -- The result is that a `VE` can produce an arbitrarily long chain of @`Union` r@ -- effects, terminated with a pure value.-data VE r w = Val w | E !(Union r (VE r w))-  deriving Typeable+--+-- As is made explicit here, `VE` is simply the Free monad resulting from the+-- @`Union` r@ functor.+type VE r = Free (Union r)  fromVal :: VE r w -> w-fromVal (Val w) = w+fromVal (Pure w) = w fromVal _ = error "extensible-effects: fromVal was called on a non-terminal effect." {-# INLINE fromVal #-} --- | Basic datatype returned by all computations with extensible effects.--- The type @r@ is the type of effects that can be handled,--- and @a@ is the type of value that is returned.-newtype Eff r a = Eff { runEff :: forall w. (a -> VE r w) -> VE r w }-  deriving Typeable--instance Functor (Eff r) where-    fmap f m = Eff $ \k -> runEff m (k . f)-    {-# INLINE fmap #-}--instance Applicative (Eff r) where-    pure = return-    (<*>) = ap--instance Monad (Eff r) where-    return x = Eff $ \k -> k x-    {-# INLINE return #-}--    m >>= f = Eff $ \k -> runEff m (\v -> runEff (f v) k)-    {-# INLINE (>>=) #-}+-- | Basic datatype returned by all computations with extensible effects. The+-- @`Eff` r@ type is a type synonym where the type @r@ is the type of effects+-- that can be handled, and the missing type @a@ (from the type application) is+-- the type of value that is returned.+--+-- As is made explicit below, the `Eff` type is simply the application of the+-- Codensity transformer to `VE`:+--+--     @type `Eff` r a = `Codensity` (`VE` r) a@+--+-- This is done to gain the asymptotic speedups for scenarios where there is a+-- single 'execution' stage where the built up monadic computation gets+-- executed. For scenarios where the computation execution and building stages+-- are interspersed, the reflection without remorse techniques would be a+-- better fit. See <https://github.com/atzeus/reflectionwithoutremorse>.+type Eff r = Codensity (VE r)+#if __GLASGOW_HASKELL__ >= 708+-- as of version 4.1.0.1 Codensity in kan-extensions does not have a a Typeable+-- instance. it doesn't seem possible to be able to define an orphan Typeable+-- instance for Codensity in ghc-7.6+deriving instance Typeable Codensity+#endif  -- | Given a method of turning requests into results, -- we produce an effectful computation. send :: (forall w. (a -> VE r w) -> Union r (VE r w)) -> Eff r a-send f = Eff (E . f)+send f = Codensity (Free . f) {-# INLINE send #-}  -- | Tell an effectful computation that you're ready to start running effects -- and return a value. admin :: Eff r w -> VE r w-admin (Eff m) = m Val+admin (Codensity m) = m Pure {-# INLINE admin #-}  -- | Get the result from a pure computation.@@ -151,7 +162,7 @@ handleRelay u loop h = either passOn h $ decomp u   where passOn u' = send (<$> u') >>= loop   -- perhaps more efficient:-  -- passOn u' = send (\k -> fmap (\w -> runEff (loop w) k) u')+  -- passOn u' = send (\k -> fmap (\w -> runCodensity (loop w) k) u') {-# INLINE handleRelay #-}  -- | Given a request, either handle it or relay it. Both the handler
src/Control/Eff/Choose.hs view
@@ -40,8 +40,8 @@ runChoice :: forall a r. Eff (Choose :> r) a -> Eff r [a] runChoice m = loop (admin m)  where-  loop (Val x)  = return [x]-  loop (E u)    = handleRelay u loop (\(Choose lst k) -> handle lst k)+  loop (Pure x)  = return [x]+  loop (Free u)    = handleRelay u loop (\(Choose lst k) -> handle lst k)    handle :: [t] -> (t -> VE (Choose :> r) a) -> Eff r [a]   handle [] _  = return []
src/Control/Eff/Coroutine.hs view
@@ -39,6 +39,6 @@ runC :: Typeable a => Eff (Yield a :> r) w -> Eff r (Y r a w) runC m = loop (admin m)   where-    loop (Val x) = return (Done x)-    loop (E u)   = handleRelay u loop $+    loop (Pure x) = return (Done x)+    loop (Free u)   = handleRelay u loop $                     \(Yield x k) -> return (Y x (loop . k))
src/Control/Eff/Cut.hs view
@@ -68,8 +68,8 @@ -- It completely handles CutFalse effects but not non-determinism. call :: Member Choose r => Eff (Exc CutFalse :> r) a -> Eff r a call m = loop [] (admin m) where- loop jq (Val x) = return x `mplus'` next jq          -- (C2)- loop jq (E u) = case decomp u of+ loop jq (Pure x) = return x `mplus'` next jq          -- (C2)+ loop jq (Free u) = case decomp u of     Right (Exc CutFalse) -> mzero'  -- drop jq (F2)     Left u' -> check jq u' 
src/Control/Eff/Exception.hs view
@@ -49,8 +49,8 @@ runExc :: Typeable e => Eff (Exc e :> r) a -> Eff r (Either e a) runExc = loop . admin  where-  loop (Val x)  = return (Right x)-  loop (E u)    = handleRelay u loop (\(Exc e) -> return (Left e))+  loop (Pure x)  = return (Right x)+  loop (Free u)    = handleRelay u loop (\(Exc e) -> return (Left e))  -- | Runs a failable effect, such that failed computation return 'Nothing', and --   'Just' the return value on success.@@ -66,8 +66,8 @@          -> Eff r a catchExc m handle = loop (admin m)  where-  loop (Val x)  = return x-  loop (E u)    = interpose u loop (\(Exc e) -> handle e)+  loop (Pure x)  = return x+  loop (Free u)    = interpose u loop (\(Exc e) -> handle e)  -- | Add a default value (i.e. failure handler) to a fallible computation. -- This hides the fact that a failure happened.
src/Control/Eff/Fresh.hs view
@@ -25,6 +25,6 @@ runFresh :: (Typeable i, Enum i) => Eff (Fresh i :> r) w -> i -> Eff r w runFresh m s0 = loop s0 (admin m)   where-    loop _ (Val x) = return x-    loop s (E u)   = handleRelay u (loop s) $+    loop _ (Pure x) = return x+    loop s (Free u)   = handleRelay u (loop s) $                           \(Fresh k) -> (loop $! succ s) (k s)
src/Control/Eff/Lift.hs view
@@ -56,5 +56,5 @@ -- we only allow a single Lifted Monad. runLift :: (Monad m, Typeable1 m) => Eff (Lift m :> ()) w -> m w runLift m = loop (admin m) where- loop (Val x) = return x- loop (E u) = prjForce u $ \(Lift m' k) -> m' >>= loop . k+ loop (Pure x) = return x+ loop (Free u) = prjForce u $ \(Lift m' k) -> m' >>= loop . k
src/Control/Eff/Reader/Lazy.hs view
@@ -33,8 +33,8 @@       -> Eff r a local f m = do   e <- f <$> ask-  let loop (Val x) = return x-      loop (E u) = interpose u loop (\(Reader k) -> loop (k e))+  let loop (Pure x) = return x+      loop (Free u) = interpose u loop (\(Reader k) -> loop (k e))   loop (admin m)  -- | Request the environment value using a transformation function.@@ -46,5 +46,5 @@ runReader :: Typeable e => Eff (Reader e :> r) w -> e -> Eff r w runReader m e = loop (admin m)   where-    loop (Val x) = return x-    loop (E u) = handleRelay u loop (\(Reader k) -> loop (k e))+    loop (Pure x) = return x+    loop (Free u) = handleRelay u loop (\(Reader k) -> loop (k e))
src/Control/Eff/Reader/Strict.hs view
@@ -34,8 +34,8 @@       -> Eff r a local f m = do   e <- f <$> ask-  let loop (Val x) = return x-      loop (E u) = interpose u loop (\(Reader k) -> loop (k e))+  let loop (Pure x) = return x+      loop (Free u) = interpose u loop (\(Reader k) -> loop (k e))   loop (admin m)  -- | Request the environment value using a transformation function.@@ -46,5 +46,5 @@ -- all Reader requests are fully handled. runReader :: Typeable e => Eff (Reader e :> r) w -> e -> Eff r w runReader m !e = loop (admin m) where- loop (Val x) = return x- loop (E u) = handleRelay u loop (\(Reader k) -> loop (k e))+ loop (Pure x) = return x+ loop (Free u) = handleRelay u loop (\(Reader k) -> loop (k e))
src/Control/Eff/State/Lazy.hs view
@@ -40,8 +40,8 @@          -> Eff (State s :> r) w  -- ^ Effect incorporating State          -> Eff r (s, w)          -- ^ Effect containing final state and a return value runState s0 = loop s0 . admin where- loop s (Val x) = return (s, x)- loop s (E u)   = handleRelay u (loop s) $+ loop s (Pure x) = return (s, x)+ loop s (Free u)   = handleRelay u (loop s) $                        \(State t k) -> let s' = t s                                        in loop s' (k s') 
src/Control/Eff/State/Strict.hs view
@@ -53,8 +53,8 @@          -> Eff (State s :> r) w  -- ^ Effect incorporating State          -> Eff r (s, w)          -- ^ Effect containing final state and a return value runState s0 = loop s0 . admin where- loop !s (Val x) = return (s, x)- loop !s (E u)   = handleRelay u (loop s) $+ loop !s (Pure x) = return (s, x)+ loop !s (Free u)   = handleRelay u (loop s) $                        \(State t k) -> let s' = t s                                        in loop s' (k s') 
src/Control/Eff/Trace.hs view
@@ -24,5 +24,5 @@ runTrace :: Eff (Trace :> ()) w -> IO w runTrace m = loop (admin m)   where-    loop (Val x) = return x-    loop (E u)   = prjForce u $ \(Trace s k) -> putStrLn s >> loop (k ())+    loop (Pure x) = return x+    loop (Free u)   = prjForce u $ \(Trace s k) -> putStrLn s >> loop (k ())
src/Control/Eff/Writer/Lazy.hs view
@@ -31,8 +31,8 @@ censor :: (Typeable w, Member (Writer w) r) => (w -> w) -> Eff r a -> Eff r a censor f = loop . admin   where-    loop (Val x) = return x-    loop (E u) = interpose u loop+    loop (Pure x) = return x+    loop (Free u) = interpose u loop                $ \(Writer w v) -> tell (f w) >> loop v  -- | Handle Writer requests, using a user-provided function to accumulate values.@@ -41,8 +41,8 @@   where     first f (x, y) = (f x, y) -    loop (Val x) = return (b, x)-    loop (E u) = handleRelay u loop+    loop (Pure x) = return (b, x)+    loop (Free u) = handleRelay u loop                  $ \(Writer w v) -> first (accum w) <$> loop v  -- | Handle Writer requests by taking the first value provided.
src/Control/Eff/Writer/Strict.hs view
@@ -32,8 +32,8 @@ censor :: (Typeable w, Member (Writer w) r) => (w -> w) -> Eff r a -> Eff r a censor f = loop . admin   where-    loop (Val x) = return x-    loop (E u) = interpose u loop+    loop (Pure x) = return x+    loop (Free u) = interpose u loop                $ \(Writer w v) -> tell (f w) >> loop v  -- | Handle Writer requests, using a user-provided function to accumulate values.@@ -42,8 +42,8 @@   where     first f (x, y) = (f x, y) -    loop (Val x) = return (b, x)-    loop (E u) = handleRelay u loop+    loop (Pure x) = return (b, x)+    loop (Free u) = handleRelay u loop                  $ \(Writer w v) -> first (accum w) <$> loop v  -- | Handle Writer requests by taking the first value provided.
src/Data/OpenUnion.hs view
@@ -36,7 +36,7 @@  import Control.Applicative ((<$>)) import Data.Typeable-#if __GLASGOW_HASKELL__ >= 781+#if __GLASGOW_HASKELL__ >= 708 import Data.OpenUnion.Internal.OpenUnion2 #else import Data.OpenUnion.Internal.OpenUnion1
src/Data/OpenUnion/Internal/Base.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeOperators #-}@@ -23,6 +24,7 @@ -- NOTE: exposing the constructor below allows users to bypass the type -- system. See 'Data.OpenUnion.unsafeReUnion' for example. data Union r v = forall t. (Functor t, Typeable1 t) => Union (t v)+                 deriving Typeable  instance Functor (Union r) where     {-# INLINE fmap #-}@@ -31,3 +33,6 @@ -- | A sum data type, for composing effects infixr 1 :> data ((a :: * -> *) :> b)+#if __GLASGOW_HASKELL__ >= 708+  deriving Typeable+#endif
test/Test.hs view
@@ -60,7 +60,7 @@            => [a]            -> Eff e ()     sumAll = mapM_ (LazyS.modify . (+))-    +     writeAndAdd :: (Member (LazyW.Writer Integer) e, Member (LazyS.State Integer) e)                 => [Integer]                 -> Eff e ()@@ -159,6 +159,24 @@     possiblyAmbiguous :: (Typeable1 m, Monad m, SetMember Lift (Lift m) r) => Eff r ()     possiblyAmbiguous = lift $ return () +#if __GLASGOW_HASKELL__ >= 708+testNestedEff :: Property+testNestedEff = forAll arbitrary (\x -> property (qu x == x))+  where+    qu :: Bool -> Bool+    qu x = run $ StrictR.runReader (readerAp x) readerId++    readerAp :: Bool -> Eff (StrictR.Reader (Eff (StrictR.Reader Bool :> ()) Bool) :> ()) Bool+    readerAp x = do+      f <- StrictR.ask+      return . run $ StrictR.runReader f x++    readerId :: Eff (StrictR.Reader Bool :> ()) Bool+    readerId = do+      x <- StrictR.ask+      return x+#endif+ tests =   [ testProperty "Documentation example." testDocs   , testProperty "Test Writer.Lazy.censor." testCensor@@ -171,4 +189,7 @@   , testCase "Test runFirstWriter laziness." testFirstWriterLaziness   , testCase "Test failure effect." testFailure   , testCase "Test lift building." testLift+#if __GLASGOW_HASKELL__ >= 708+  , testProperty "Test nested Eff." testNestedEff+#endif   ]