packages feed

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 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