effects 0 → 0.1
raw patch · 10 files changed
+78/−29 lines, 10 filessetup-changedPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Control.Effects: ioHandler :: Handler a IO a a
- Control.Effects: type Cont r = ContT r Identity
- Control.Effects: Handler :: (a -> m e) -> (e -> m r) -> Handler e m a r
+ Control.Effects: Handler :: (a -> m e) -> (e -> m r) -> Handler e r m a
- Control.Effects: data Handler e m a r
+ Control.Effects: data Handler e r m a
- Control.Effects: fin :: Handler e m a r -> e -> m r
+ Control.Effects: fin :: Handler e r m a -> e -> m r
- Control.Effects: io :: AutoLift (ContT () IO) n => IO a -> n a
+ Control.Effects: io :: AutoLift IO n => IO a -> n a
- Control.Effects: operation :: (m ~ (ContT r m'), AutoLift m n) => Proxy m -> ((a -> m' r) -> m' r) -> n a
+ Control.Effects: operation :: (c ~ (ContT e m), AutoLift c n) => Proxy c -> ((a -> m e) -> m e) -> n a
- Control.Effects: ret :: Handler e m a r -> a -> m e
+ Control.Effects: ret :: Handler e r m a -> a -> m e
- Control.Effects: run :: Cont a a -> a
+ Control.Effects: run :: Identity a -> a
- Control.Effects: runIO :: ContT () IO () -> IO ()
+ Control.Effects: runIO :: IO () -> IO ()
- Control.Effects: with :: Monad m => Handler e m a r -> (Proxy (ContT e m) -> ContT e m a) -> m r
+ Control.Effects: with :: Monad m => Handler e r m a -> (Proxy (ContT e m) -> ContT e m a) -> m r
- Control.Effects.Cont: reset :: Monad m => Handler a m a a
+ Control.Effects.Cont: reset :: Monad m => Handler a a m a
- Control.Effects.Either: catchEither :: Monad m => (e -> m a) -> Handler (m (Either e a)) m a a
+ Control.Effects.Either: catchEither :: Monad m => (e -> m a) -> Handler (Either e a) a m a
- Control.Effects.Either: throwEither :: (c ~ (ContT (m (Either e r)) m), AutoLift c n, Monad m) => Proxy c -> e -> n Void
+ Control.Effects.Either: throwEither :: (c ~ (ContT (Either e r) m), AutoLift c n, Monad m) => Proxy c -> e -> n Void
- Control.Effects.Error: catchError :: Monad m => (e -> m a) -> Handler ((e -> m a) -> m a) m a a
+ Control.Effects.Error: catchError :: Monad m => (e -> m a) -> Handler ((e -> m a) -> m a) a m a
- Control.Effects.Set: set :: (Monad m, Ord a) => Handler (Set a) m a (Set a)
+ Control.Effects.Set: set :: (Monad m, Ord a) => Handler (Set a) (Set a) m a
- Control.Effects.State: ref :: Monad m => s -> Handler (s -> m a) m a a
+ Control.Effects.State: ref :: Monad m => s -> Handler (s -> m a) a m a
- Control.Effects.Writer: writer :: (Monad m, Monoid w) => Handler (w, a) m a (w, a)
+ Control.Effects.Writer: writer :: (Monad m, Monoid w) => Handler (w, a) (w, a) m a
Files
- Setup.hs +0/−2
- Setup.lhs +3/−0
- effects.cabal +1/−1
- src/Control/Effects.hs +64/−16
- src/Control/Effects/Cont.hs +1/−1
- src/Control/Effects/Either.hs +5/−5
- src/Control/Effects/Error.hs +1/−1
- src/Control/Effects/Set.hs +1/−1
- src/Control/Effects/State.hs +1/−1
- src/Control/Effects/Writer.hs +1/−1
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
effects.cabal view
@@ -1,5 +1,5 @@ name: effects-version: 0+version: 0.1 synopsis: Computational Effects description: An alternative to Monad Transformers.
src/Control/Effects.hs view
@@ -1,33 +1,81 @@ {-# LANGUAGE MultiParamTypeClasses, TypeFamilies, ScopedTypeVariables, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}-module Control.Effects (Handler(..), with, operation, run, runIO, io, ioHandler, Cont, ContT, Proxy, AutoLift) where+module Control.Effects ( + -- * Running effects+ -- $rundoc+ with+ , run+ -- * Defining effects + -- $defdoc+ , Handler(..)+ , operation+ -- * I/O+ , runIO+ , io+ -- * Effects machinery+ , ContT+ , Proxy+ , AutoLift++) where+ import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Cont import Data.Functor.Identity -data Handler e m a r = Handler- { ret :: a -> m e- , fin :: e -> m r- }+-- $rundoc+-- Here's an example how to use the state effect from 'Control.Effects.State'.+--+-- > example :: Int+-- > example = run $ do+-- > with (ref 10) $ \u -> do+-- > val <- get u+-- > put u (val + 5)+-- > get u -with :: Monad m => Handler e m a r -> (Proxy (ContT e m) -> ContT e m a) -> m r+-- | @with@ takes a handler and creates a new @Proxy@ (effect identifier).+-- The @Proxy@ is passed on to a function which can use it to do operations with it.+with :: Monad m => Handler e r m a -> (Proxy (ContT e m) -> ContT e m a) -> m r with h f = runContT (f Proxy) (ret h) >>= fin h -operation :: forall m m' n a r. (m ~ ContT r m', AutoLift m n) => Proxy m -> ((a -> m' r) -> m' r) -> n a-operation p f = autolift p (Proxy :: Proxy n) (ContT f)+-- | Unwrap the result of the top-level effect.+run :: Identity a -> a+run = runIdentity -run :: Cont a a -> a-run m = runCont m id +-- $defdoc+-- Here's and example how to define the state effect from 'Control.Effects.State'.+--+-- > ref :: Monad m => s -> Handler (s -> m a) a m a+-- > ref s_init = Handler+-- > { ret = return . return . return+-- > , fin = \f -> f s_init+-- > }+-- >+-- > get p = operation p $ \k -> return $ \s -> do r <- k s; r s+-- > put p s = operation p $ \k -> return $ \_ -> do r <- k (); r s+ +-- | A @Handler e r m a@ is a handler of effects with type @e@. +-- The @ret@ field provides a function to lift pure values into the effect.+-- The @fin@ field provides a function to extract a final value of type @r@ from the effect.+-- The parameter @m@ should narmally be left polymorphic, it's the monad that handles the other effects.+data Handler e r m a = Handler+ { ret :: a -> m e+ , fin :: e -> m r+ } -ioHandler :: Handler a IO a a-ioHandler = Handler return return+-- | Define an operation, which is autolifted so it can be used inside other effects.+operation :: forall c m n a e. (c ~ ContT e m, AutoLift c n) => Proxy c -> ((a -> m e) -> m e) -> n a+operation p f = autolift p (Proxy :: Proxy n) (ContT f) -runIO :: ContT () IO () -> IO ()-runIO m = with ioHandler (const m) -io :: AutoLift (ContT () IO) n => IO a -> n a-io m = operation (Proxy :: Proxy (ContT () IO)) (m >>=)+-- | Variant of 'run' that allows I/O effects. (Just the identity function, but it helps the type checker.)+runIO :: IO () -> IO ()+runIO = id++-- | Convert an 'IO' action to an I/O effect operation.+io :: AutoLift IO n => IO a -> n a+io m = autolift (Proxy :: Proxy IO) (Proxy :: Proxy n) m data Proxy (m :: * -> *) = Proxy
src/Control/Effects/Cont.hs view
@@ -6,7 +6,7 @@ shift :: (c ~ ContT r m, AutoLift c n, Monad m) => Proxy c -> ((m a -> m r) -> m r) -> n a shift p c = operation p $ \k -> c (>>= k) -reset :: Monad m => Handler a m a a+reset :: Monad m => Handler a a m a reset = Handler { ret = return , fin = return
src/Control/Effects/Either.hs view
@@ -4,11 +4,11 @@ import Control.Effects import Data.Void -throwEither :: (c ~ ContT (m (Either e r)) m, AutoLift c n, Monad m) => Proxy c -> e -> n Void-throwEither p e = operation p $ \_ -> return . return $ Left e+throwEither :: (c ~ ContT (Either e r) m, AutoLift c n, Monad m) => Proxy c -> e -> n Void+throwEither p e = operation p $ \_ -> return $ Left e -catchEither :: Monad m => (e -> m a) -> Handler (m (Either e a)) m a a+catchEither :: Monad m => (e -> m a) -> Handler (Either e a) a m a catchEither h = Handler- { ret = return . return . return- , fin = \m -> m >>= either h return+ { ret = return . return+ , fin = either h return }
src/Control/Effects/Error.hs view
@@ -7,7 +7,7 @@ throwError :: (c ~ ContT ((e -> m r) -> m r) m, AutoLift c n, Monad m) => Proxy c -> e -> n Void throwError p e = operation p $ \_ -> return $ \h -> h e -catchError :: Monad m => (e -> m a) -> Handler ((e -> m a) -> m a) m a a+catchError :: Monad m => (e -> m a) -> Handler ((e -> m a) -> m a) a m a catchError h = Handler { ret = return . return . return , fin = \f -> f h
src/Control/Effects/Set.hs view
@@ -10,7 +10,7 @@ sets <- mapM k as return $ Set.unions sets -set :: (Monad m, Ord a) => Handler (Set.Set a) m a (Set.Set a)+set :: (Monad m, Ord a) => Handler (Set.Set a) (Set.Set a) m a set = Handler { ret = return . Set.singleton , fin = return
src/Control/Effects/State.hs view
@@ -9,7 +9,7 @@ put :: (c ~ ContT (s -> m r) m, AutoLift c n, Monad m) => Proxy c -> s -> n () put p s' = operation p $ \k -> return $ \_ -> do r <- k (); r s' -ref :: Monad m => s -> Handler (s -> m a) m a a+ref :: Monad m => s -> Handler (s -> m a) a m a ref s_init = Handler { ret = return . return . return , fin = \f -> f s_init
src/Control/Effects/Writer.hs view
@@ -7,7 +7,7 @@ tell :: (c ~ ContT (w, r) m, AutoLift c n, Monad m, Monoid w) => Proxy c -> w -> n () tell p w = operation p $ \k -> do (w', r) <- k (); return (w `mappend` w', r) -writer :: (Monad m, Monoid w) => Handler (w, a) m a (w, a)+writer :: (Monad m, Monoid w) => Handler (w, a) (w, a) m a writer = Handler { ret = \a -> return (mempty, a) , fin = return