error-continuations (empty) → 0.1.0.0
raw patch · 8 files changed
+564/−0 lines, 8 filesdep +basedep +eitherdep +mtlsetup-changed
Dependencies added: base, either, mtl, transformers
Files
- LICENSE +25/−0
- Setup.hs +2/−0
- error-continuations.cabal +72/−0
- src/Control/Error/Cont/Util.hs +28/−0
- src/Control/Monad/EitherCont.hs +75/−0
- src/Control/Monad/MaybeCont.hs +66/−0
- src/Control/Monad/Trans/EitherCont.hs +207/−0
- src/Control/Monad/Trans/MaybeCont.hs +89/−0
+ LICENSE view
@@ -0,0 +1,25 @@+This is free and unencumbered software released into the public domain.++Anyone is free to copy, modify, publish, use, compile, sell, or+distribute this software, either in source code form or as a compiled+binary, for any purpose, commercial or non-commercial, and by any+means.++In jurisdictions that recognize copyright laws, the author or authors+of this software dedicate any and all copyright interest in the+software to the public domain. We make this dedication for the benefit+of the public at large and to the detriment of our heirs and+successors. We intend this dedication to be an overt act of+relinquishment in perpetuity of all present and future rights to this+software under copyright law.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+OTHER DEALINGS IN THE SOFTWARE.++For more information, please refer to <http://unlicense.org>+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ error-continuations.cabal view
@@ -0,0 +1,72 @@+-- The name of the package.+name: error-continuations++-- The package version. See the Haskell package versioning policy (PVP) +-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary: +-+------- breaking API changes+-- | | +----- non-breaking API additions+-- | | | +--- code changes with no API change+version: 0.1.0.0++-- A short (one-line) description of the package.+synopsis: Error Continuations++-- A longer description of the package.+-- description: ++-- URL for the project homepage or repository.+homepage: https://github.com/echatav/error-continuations++-- The license under which the package is released.+license: PublicDomain++-- The file containing the license text.+license-file: LICENSE++-- The package author(s).+author: Eitan Chatav++-- An email address to which users can send suggestions, bug reports, and +-- patches.+maintainer: eitan.chatav@gmail.com++category: Control++build-type: Simple++-- Extra files to be distributed with the package, such as examples or a +-- README.+-- extra-source-files: ++-- Constraint on the version of Cabal needed to build this package.+cabal-version: >=1.10+++library+ -- Modules exported by the library.+ exposed-modules:+ Control.Error.Cont.Util,+ Control.Monad.EitherCont,+ Control.Monad.MaybeCont,+ Control.Monad.Trans.EitherCont,+ Control.Monad.Trans.MaybeCont+ + -- Modules included in this library but not exported.+ -- other-modules: + + -- LANGUAGE extensions used by modules in this package.+ -- other-extensions: + + -- Other library packages from which modules are imported.+ build-depends:+ base >=4.7 && <4.8,+ transformers >=0.4 && <0.5,+ mtl >=2.2 && <2.3,+ either >= 4.3 && <4.4+ + -- Directories containing source files.+ hs-source-dirs: src+ + -- Base language which the package is written in.+ default-language: Haskell2010
+ src/Control/Error/Cont/Util.hs view
@@ -0,0 +1,28 @@+{-|+Module : Control.Error.Cont.Util+Description : Utility functions for error continuations+Copyright : (c) Eitan Chatav, 2015+License : PublicDomain+Maintainer : eitan.chatav@gmail.com+Stability : experimental++This module provides utility functions to convert between 'MaybeContT' and+'EitherContT' computations.+-}++module Control.Error.Cont.Util+ ( hush+ , note+ ) where++import Control.Applicative+import Control.Monad.Trans.EitherCont+import Control.Monad.Trans.MaybeCont++-- |Suppress the nothing continuation of an 'EitherContT'+hush :: EitherContT a l m r -> MaybeContT a m r+hush ec = MaybeContT $ \ma k -> runEitherContT ec (const ma) k++-- |Tag the nothing continuation of a 'MaybeContT'+note :: l -> MaybeContT a m r -> EitherContT a l m r+note l mc = EitherContT $ \kl kr -> runMaybeContT mc (kl l) kr
+ src/Control/Monad/EitherCont.hs view
@@ -0,0 +1,75 @@+{-|+Module : Control.Monad.EitherCont+Description : The 'EitherCont' type and API+Copyright : (c) Eitan Chatav, 2015+License : PublicDomain+Maintainer : eitan.chatav@gmail.com+Stability : experimental++The 'EitherCont' type and API provide an idiomatic way to handle errors in+continuation passing style.+-}++module Control.Monad.EitherCont+ ( EitherCont+ , EitherContT()+ , eitherCont+ , runEitherCont+ , liftEither+ , fmapL+ , bimapEC+ , throwEC+ , apL+ , catchEC+ , liftL+ , flipEC+ , mapEitherCont+ , withEitherContL+ , withEitherContR+ , callCCL+ ) where++import Control.Monad.Trans.EitherCont+import Data.Functor.Identity++-- |'EitherCont' 'a' 'l' 'r' is a CPS computation that produces an intermediate+-- result of type 'a' within a CPS computation which produces either a success+-- of type 'r' or failure of type 'l'.+type EitherCont a l r = EitherContT a l Identity r++-- |Construct a continuation-passing computation from a function.+eitherCont :: ((l -> a) -> (r -> a) -> a) -> EitherCont a l r+eitherCont ec = EitherContT $ \kl kr -> Identity $+ ec (runIdentity . kl) (runIdentity . kr)++-- |The result of running a CPS computation with given failure and success+-- continuations.+--+-- prop> runEitherCont . eitherCont = id+-- prop> eitherCont . runEitherCont = id+runEitherCont :: EitherCont a l r -> (l -> a) -> (r -> a) -> a+runEitherCont ec kl kr = runIdentity $+ runEitherContT ec (Identity . kl) (Identity . kr)++-- |'liftEither' embeds 'Either' in 'EitherCont' 'a'.+liftEither :: Either l r -> EitherCont a l r+liftEither e = eitherCont $ \kl kr -> either kl kr e++-- |Apply a function to transform the result of a continuation-passing+-- computation.+mapEitherCont :: (a -> a) -> EitherCont a l r -> EitherCont a l r+mapEitherCont = mapEitherContT . fmap++-- |Apply a function to transform the success continuation passed to a+-- continuation-passing computation.+withEitherContR :: ((r' -> a) -> r -> a)+ -> EitherCont a l r+ -> EitherCont a l r'+withEitherContR f = withEitherContTR ((Identity .) . f . (runIdentity .))++-- |Apply a function to transform the failure continuation passed to an+-- continuation-passing computation.+withEitherContL :: ((l' -> a) -> l -> a)+ -> EitherCont a l r+ -> EitherCont a l' r+withEitherContL f = withEitherContTL ((Identity .) . f . (runIdentity .))
+ src/Control/Monad/MaybeCont.hs view
@@ -0,0 +1,66 @@+{-|+Module : Control.Monad.MaybeContT+Description : The 'MaybeCont' type and API+Copyright : (c) Eitan Chatav, 2015+License : PublicDomain+Maintainer : eitan.chatav@gmail.com+Stability : experimental++The 'MaybeCont' type and API provide an idiomatic way to handle possibly+failing computations in continuation passing style.+-}++module Control.Monad.MaybeCont+ ( MaybeCont+ , MaybeContT()+ , maybeCont+ , runMaybeCont+ , liftMaybe+ , nothingC+ , mapMaybeCont+ , withMaybeContJust+ , withMaybeContNothing+ ) where++import Control.Monad.Trans.MaybeCont+import Data.Functor.Identity++-- |'MaybeCont' 'a' 'r' is a CPS computation that produces an intermediate+-- result of type 'a' within a CPS computation which produces either a just+-- or nothing.+type MaybeCont a r = MaybeContT a Identity r++-- |Construct a continuation-passing computation from a function.+maybeCont :: (a -> (r -> a) -> a) -> MaybeCont a r+maybeCont mc = MaybeContT $ \ma k -> Identity $+ mc (runIdentity ma) (runIdentity . k)++-- |The result of running a CPS computation with given nothing and just+-- continuations.+--+-- prop> runMaybeCont . maybeCont = id+-- prop> maybeCont . runMaybeCont = id+runMaybeCont :: MaybeCont a r -> (a -> (r -> a) -> a)+runMaybeCont mc a k = runIdentity $+ runMaybeContT mc (Identity a) (Identity . k)++-- |'liftMaybe' embeds 'Maybe' in 'MaybeCont' 'a'.+liftMaybe :: Maybe r -> MaybeCont a r+liftMaybe may = maybeCont $ \a k -> maybe a k may++-- |Apply a function to transform the result of a continuation-passing+-- computation.+mapMaybeCont :: (a -> a) -> MaybeCont a r -> MaybeCont a r+mapMaybeCont = mapMaybeContT . fmap++-- |Apply a function to transform the just continuation passed to a+-- continuation-passing computation.+withMaybeContJust :: ((r' -> a) -> r -> a)+ -> MaybeCont a r+ -> MaybeCont a r'+withMaybeContJust f = withMaybeContTJust ((Identity .) . f . (runIdentity .))++-- |Apply a function to transform the nothing continuation passed to an+-- continuation-passing computation.+withMaybeContNothing :: (a -> a) -> MaybeCont a r -> MaybeCont a r+withMaybeContNothing = withMaybeContTNothing . fmap
+ src/Control/Monad/Trans/EitherCont.hs view
@@ -0,0 +1,207 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}++{-|+Module : Control.Monad.Trans.EitherCont+Description : The 'EitherContT' type and API+Copyright : (c) Eitan Chatav, 2015+License : PublicDomain+Maintainer : eitan.chatav@gmail.com+Stability : experimental++The 'EitherContT' type and API provide an idiomatic way to handle errors in+continuation passing style over some base monad.+-}++module Control.Monad.Trans.EitherCont+ ( EitherContT+ ( EitherContT+ , runEitherContT+ )+ , liftEitherT+ , fmapL+ , bimapEC+ , throwEC+ , apL+ , catchEC+ , handleEC+ , (<?<)+ , (>?>)+ , liftL+ , flipEC+ , mapEitherContT+ , withEitherContTR+ , withEitherContTL+ , callCCL+ , lowerMonadError+ , liftMonadError+ ) where++import Control.Applicative+import Control.Monad.Cont+import Control.Monad.Error.Class+import Control.Monad.IO.Class+import Control.Monad.Trans+import Control.Monad.Trans.Either++-- |The 'EitherContT' 'a' 'l' 'm' 'r' type encodes a sum type monad transformer+-- in continuation passing style which is separately monadic in both 'l' and+-- 'r'. Interestingly, this property holds for any type constructor 'm'.+newtype EitherContT a l m r+ -- |Construct a continuation-passing computation from a function.+ = EitherContT+ { -- |The result of running a CPS computation with given failure and+ -- success continuations.+ runEitherContT :: (l -> m a) -> (r -> m a) -> m a+ }++-- |'liftEitherT' embeds 'EitherT' in 'EitherContT' 'a'.+liftEitherT :: Monad m => EitherT l m r -> EitherContT a l m r+liftEitherT e = EitherContT $ \kl kr -> eitherT kl kr e++-- |The 'Functor' instance encodes functoriality of 'EitherContT' 'a' 'l' 'm'+-- 'r' in 'r'.+instance Functor (EitherContT a l m) where+ fmap f ec = EitherContT $ \kl kr -> runEitherContT ec kl (kr . f)++-- |'fmapL' encodes functoriality of 'EitherContT' 'a' 'l' 'm' 'r' in 'l'.+fmapL :: (l -> l') -> EitherContT a l m r -> EitherContT a l' m r+fmapL f ec = EitherContT $ \kl kr -> runEitherContT ec (kl . f) kr++-- |'bimapEC' encodes bifunctoriality of 'EitherContT' 'a' 'l' 'm' 'r' in 'l'+-- and 'r'.+--+-- prop> bimapEC f id = fmapL f+-- prop> bimapEC id f = fmap f+bimapEC :: (l -> l') -> (r -> r')+ -> EitherContT a l m r+ -> EitherContT a l' m r'+bimapEC fl fr ec = EitherContT $ \kl kr -> runEitherContT ec (kl . fl) (kr . fr)++-- |The 'Applicative' instance encodes applicativity of 'EitherContT' 'a' 'l'+-- 'm' 'r' in 'r'.+instance Applicative (EitherContT a l m) where+ pure r = EitherContT $ \_ kr -> kr r+ ecf <*> ec = EitherContT $ \kl kr ->+ runEitherContT ecf kl (\f -> runEitherContT ec kl (kr . f))++-- |'throwEC' encodes the applicative/monadic unit of 'EitherContT' 'a' 'l' 'm'+-- 'r' in 'l'.+throwEC :: l -> EitherContT a l m r+throwEC l = EitherContT $ \kl _ -> kl l++-- |'apL' encodes applicativity of 'EitherContT' 'a' 'l' 'm' 'r' in 'l'.+apL :: EitherContT a (l -> l') m r+ -> EitherContT a l m r+ -> EitherContT a l' m r+apL ecf ec = EitherContT $ \kl kr ->+ runEitherContT ecf (\f -> runEitherContT ec (kl . f) kr) kr++-- |The 'Monad' instance encodes monadicity of 'EitherContT' 'a' 'l' 'm' 'r' in+-- 'r'.+instance Monad (EitherContT a l m) where+ return = pure+ ec >>= ecf = EitherContT $ \kl kr ->+ runEitherContT ec kl (\r -> runEitherContT (ecf r) kl kr)++-- |'throwEC' and 'catchEC' encode monadicity of 'EitherContT' 'a' 'l' 'm' 'r'+-- in 'l'. The usual monad laws hold with 'throwEC' taking the role of 'return'+-- and 'catchEC' taking the role of '>>='.+--+-- prop> throwEC l `catchEC` f = f l+-- prop> ec `catchEC` throwEC = ec+-- prop> (ec `catchEC` f) `catchEC` g = ec `catchEC` (\l -> f l `catchEC` g)+catchEC :: EitherContT a l m r+ -> (l -> EitherContT a l' m r)+ -> EitherContT a l' m r+catchEC ec ecf = EitherContT $ \kl kr ->+ runEitherContT ec (\l -> runEitherContT (ecf l) kl kr) kr++-- |'handleEC' is a flipped `catchEC`.+handleEC :: (l -> EitherContT a l' m r)+ -> EitherContT a l m r+ -> EitherContT a l' m r+handleEC = flip catchEC++-- |A right-to-left, point free way to compose handlers. The monad laws look+-- more elegant, expressed in terms of '<?<'.+--+-- prop> throwEC <?< f = f = f <?< throwEC+-- prop> (h <?< g) <?< f = h <?< (g <?< f)+(<?<) :: (l' -> EitherContT a l'' m r)+ -> (l -> EitherContT a l' m r)+ -> (l -> EitherContT a l'' m r)+(<?<) g f l = g `handleEC` (f l)++-- |A left-to-right, point free way to compose handlers.+(>?>) :: (l -> EitherContT a l' m r)+ -> (l' -> EitherContT a l'' m r)+ -> (l -> EitherContT a l'' m r)+(>?>) = flip (<?<)+++-- |'EitherContT' 'a' 'l' 'm' 'r' is a monad transformer for 'm' in 'r'.+instance MonadTrans (EitherContT a l) where+ lift mr = EitherContT $ \_ kr -> mr >>= kr++-- |'EitherContT' 'a' 'l' 'm' 'r' is a monad transformer for 'm' in 'l'.+liftL :: Monad m => m l -> EitherContT a l m r+liftL ml = EitherContT $ \kl _ -> ml >>= kl++-- |'flipEC' encodes the symmetry of 'l' and 'r' in 'EitherContT' 'a' 'l' 'm'+-- 'r'.+--+-- prop> flipEC . flipEC = id+flipEC :: EitherContT a l m r -> EitherContT a r m l+flipEC = EitherContT . flip . runEitherContT++-- |Apply a function to transform the result of a continuation-passing+-- computation.+mapEitherContT :: (m a -> m a) -> EitherContT a l m r -> EitherContT a l m r+mapEitherContT f ec = EitherContT $ \kl kr -> f (runEitherContT ec kl kr)++-- |Apply a function to transform the success continuation passed to a+-- continuation-passing computation.+withEitherContTR :: ((r' -> m a) -> r -> m a)+ -> EitherContT a l m r+ -> EitherContT a l m r'+withEitherContTR f ec = EitherContT $ \kl kr -> runEitherContT ec kl (f kr)++-- |Apply a function to transform the failure continuation passed to an+-- continuation-passing computation.+withEitherContTL :: ((l' -> m a) -> l -> m a)+ -> EitherContT a l m r+ -> EitherContT a l' m r+withEitherContTL f ec = EitherContT $ \kl kr -> runEitherContT ec (f kl) kr++-- |Call with current success continuation.+instance MonadCont (EitherContT a l m) where+ callCC f = EitherContT $ \kl kr ->+ runEitherContT (f (\r -> (EitherContT $ \_ _ -> kr r))) kl kr++-- |Call with current failure continuation.+callCCL :: ((l -> EitherContT a l' m r) -> EitherContT a l m r)+ -> EitherContT a l m r+callCCL f = EitherContT $ \kl kr ->+ runEitherContT (f (\l -> (EitherContT $ \_ _ -> kl l))) kl kr++-- |The 'MonadError' function 'catchError' is weaker than 'catchEC' since it+-- must not change the error type.+instance MonadError l (EitherContT a l m) where+ throwError = throwEC+ catchError = catchEC++-- |'lowerMonadError' runs the continuation-passing computation, throwing on+-- failure and returning on success.+lowerMonadError :: MonadError l m => EitherContT r l m r -> m r+lowerMonadError ec = runEitherContT ec throwError return++-- |'liftMonadError' embeds a 'MonadError' computation 'm' 'r' into+-- 'EitherContT' 'a' 'l' 'm' 'r'. +--+-- 'liftMonadError' and 'lowerMonadError' are+-- one-sided inverses, making @MonadError l m => m r@ a retract of+-- 'EitherContT' 'r' 'l' 'm' 'r'.+--+-- prop> lowerMonadError . liftMonadError = id+liftMonadError :: MonadError l m => m r -> EitherContT a l m r+liftMonadError mr = EitherContT $ \kl kr -> (mr >>= kr) `catchError` kl
+ src/Control/Monad/Trans/MaybeCont.hs view
@@ -0,0 +1,89 @@+{-|+Module : Control.Monad.Trans.MaybeContT+Description : The 'MaybeContT' type and API+Copyright : (c) Eitan Chatav, 2015+License : PublicDomain+Maintainer : eitan.chatav@gmail.com+Stability : experimental++The 'MaybeContT' type and API provide an idiomatic way to handle possibly+failing computations in continuation passing style over some base monad.+-}++module Control.Monad.Trans.MaybeCont+ ( MaybeContT+ ( MaybeContT+ , runMaybeContT+ )+ , liftMaybeT+ , nothingC+ , mapMaybeContT+ , withMaybeContTJust+ , withMaybeContTNothing+ ) where++import Control.Applicative+import Control.Monad.Cont+import Control.Monad.Trans+import Control.Monad.Trans.Maybe++-- |The 'MaybeContT' 'a' 'l' 'm' 'r' type encodes a nullable monad transformer+-- in continuation passing style which is monadic in 'r'. This property holds+-- for any type constructor 'm'.+newtype MaybeContT a m r+ -- |Construct a continuation-passing computation from a function.+ = MaybeContT+ { -- |The result of running a CPS computation with given nothing and+ -- just continuations.+ runMaybeContT :: m a -> (r -> m a) -> m a+ }++-- |'liftMaybeT' embeds 'MaybeT' in 'MaybeContT' 'a'.+liftMaybeT :: Monad m => MaybeT m r -> MaybeContT a m r+liftMaybeT may = MaybeContT $ \ma k -> maybe ma k =<< runMaybeT may++-- |The 'Functor' instance encodes functoriality of 'MaybeContT' 'a' 'm'.+instance Functor (MaybeContT a m) where+ fmap f mc = MaybeContT $ \ma k -> runMaybeContT mc ma (k . f)++-- |The 'Applicative' instance encodes applicativity of 'MaybeContT' 'a' 'm'.+instance Applicative (MaybeContT a m) where+ pure r = MaybeContT $ \_ k -> k r+ mcf <*> mc = MaybeContT $ \ma k ->+ runMaybeContT mcf ma (\f -> runMaybeContT mc ma (k . f))++-- |The 'Monad' instance encodes monadicity of 'MaybeContT' 'a' 'm'.+instance Monad (MaybeContT a m) where+ return = pure+ mc >>= mcf = MaybeContT $ \ma k ->+ runMaybeContT mc ma (\r -> runMaybeContT (mcf r) ma k)++-- |'MaybeContT' 'a' is a monad transformer.+instance MonadTrans (MaybeContT a) where+ lift mr = MaybeContT $ \_ k -> mr >>= k++-- |Call with current just continuation.+instance MonadCont (MaybeContT a m) where+ callCC f = MaybeContT $ \ma k ->+ runMaybeContT (f (\r -> (MaybeContT $ \_ _ -> k r))) ma k++-- |'nothingC' is the CPS representation of 'Nothing'.+nothingC :: MaybeContT a m r+nothingC = MaybeContT $ \ma _ -> ma++-- |Apply a function to transform the result of a continuation-passing+-- computation.+mapMaybeContT :: (m a -> m a) -> MaybeContT a m r -> MaybeContT a m r+mapMaybeContT f mc = MaybeContT $ \ma k -> f (runMaybeContT mc ma k)++-- |Apply a function to transform the just continuation passed to a+-- continuation-passing computation.+withMaybeContTJust :: ((r' -> m a) -> r -> m a)+ -> MaybeContT a m r+ -> MaybeContT a m r'+withMaybeContTJust f mc = MaybeContT $ \ma k -> runMaybeContT mc ma (f k)++-- |Apply a function to transform the nothing continuation passed to a+-- continuation-passing computation.+withMaybeContTNothing :: (m a -> m a) -> MaybeContT a m r -> MaybeContT a m r+withMaybeContTNothing f mc = MaybeContT $ \ma k -> runMaybeContT mc (f ma) k