From 97bb518220d8ede752d59207e6cbd9715334788d Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Sat, 5 Dec 2009 23:05:32 +0200 Subject: [PATCH] Imported from c-m-f, new Failure based class --- Control/Failure.hs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ failure.cabal | 24 ++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 Control/Failure.hs create mode 100644 failure.cabal diff --git a/Control/Failure.hs b/Control/Failure.hs new file mode 100644 index 0000000..d01e9e3 --- /dev/null +++ b/Control/Failure.hs @@ -0,0 +1,62 @@ +{-# LANGUAGE Rank2Types #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE FlexibleContexts #-} +-- | Type classes for returning failures. +module Control.Failure + ( -- * Type classes + Failure (..) + , FunctorFailure + , ApplicativeFailure + , MonadFailure + -- * Wrapping failures + , WrapFailure (..) + -- * Convenience 'String' failure + , StringException (..) + , failureString + ) where + +import Control.Exception (throw, Exception) +import Data.Typeable (Typeable) +import Control.Applicative (Applicative) + +class Failure e f where + failure :: e -> f v +class (Functor f, Failure e f) => FunctorFailure e f +class (Applicative f, Failure e f) => ApplicativeFailure e f +class (Monad f, Applicative f, Failure e f) => MonadFailure e f + +-- These introduce the need to use undecidables and overlapping. +-- However, since they are merely type synonyms, this is acceptable. +instance (Functor f, Failure e f) => FunctorFailure e f +instance (Applicative f, Failure e f) => ApplicativeFailure e f +instance (Monad f, Applicative f, Failure e f) => MonadFailure e f + +class Failure e f => WrapFailure e f where + -- | Wrap the failure value, if any, with the given function. This is + -- useful in particular when you want all the exceptions returned from a + -- certain library to be of a certain type, even if they were generated by + -- a different library. + wrapFailure :: (forall eIn. Exception eIn => eIn -> e) -> f a -> f a + +-- | Call 'failure' with a 'String'. +failureString :: MonadFailure StringException m => String -> m a +failureString = failure . StringException + +newtype StringException = StringException String + deriving Typeable +instance Show StringException where + show (StringException s) = "StringException: " ++ s +instance Exception StringException + +-- -------------- +-- base instances +-- -------------- + +instance Failure e Maybe where failure _ = Nothing +instance Failure e [] where failure _ = [] + +instance Exception e => Failure e IO where + failure = Control.Exception.throw diff --git a/failure.cabal b/failure.cabal new file mode 100644 index 0000000..21dd395 --- /dev/null +++ b/failure.cabal @@ -0,0 +1,24 @@ +name: failure +version: 0.0.0 +Cabal-Version: >= 1.6 +build-type: Simple +license: PublicDomain +author: Pepe Iborra, Michael Snoyman, Nicolas Pouillard +maintainer: pepeiborra@gmail.com +homepage: http://github.com/snoyberg/failure +description: Typeclass for representing failures +synopsis: Typeclass for representing failures +category: Control, Monads, Failure +stability: stable + +Library + buildable: True + build-depends: base >= 4 && < 5 + ghc-options: -Wall + + exposed-modules: + Control.Failure + +source-repository head + type: git + location: git://github.com/snoyberg/failure.git