@@ -1,6 +1,34 @@
1{-# LANGUAGE DeriveDataTypeable #-}
1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE DeriveFunctor #-}
2{-# LANGUAGE DeriveFunctor #-}
4+------------------------------------------------------------------------------
6+-- Module : Database.PostgreSQL.Simple.Ok
7+-- Copyright : (c) 2011-2012 Leon P Smith
10+-- Maintainer : leon@melding-monads.com
11+-- Stability : experimental
13+-- The 'Ok' type is a simple error handler, basically equivalent to
14+-- @Either [SomeException]@. This type (without the list) was used to
15+-- handle conversion errors in early versions of postgresql-simple.
17+-- One of the primary reasons why this type was introduced is that
18+-- @Either SomeException@ had not been provided an instance for 'Alternative',
19+-- and it would have been a bad idea to provide an orphaned instance for a
20+-- commonly-used type and typeclass included in @base@.
22+-- Extending the failure case to a list of 'SomeException's enables a
23+-- more sensible 'Alternative' instance definitions: '<|>' concatinates
24+-- the list of exceptions when both cases fail, and 'empty' is defined as
25+-- 'Errors []'. Though '<|>' one could pick one of two exceptions, and
26+-- throw away the other, and have 'empty' provide a generic exception,
27+-- this avoids cases where 'empty' overrides a more informative exception
28+-- and allows you to see all the different ways your computation has failed.
30+------------------------------------------------------------------------------
4module Database.PostgreSQL.Simple.Ok where
32module Database.PostgreSQL.Simple.Ok where
6import Control.Applicative
34import Control.Applicative
@@ -8,16 +36,15 @@ import Control.Exception
8import Control.Monad(MonadPlus(..))
36import Control.Monad(MonadPlus(..))
9import Data.Typeable
37import Data.Typeable
11−newtype ManyErrors = ManyErrors [SomeException]
12− deriving (Show, Typeable)
14−instance Exception ManyErrors
16−-- FIXME: [SomeException] should probably be a difference list
39+-- FIXME: [SomeException] should probably be something else, maybe
40+-- a difference list (or a tree?)
18data Ok a = Errors [SomeException] | Ok !a
42data Ok a = Errors [SomeException] | Ok !a
19 deriving(Show, Typeable, Functor)
43 deriving(Show, Typeable, Functor)
45+-- | Two 'Errors' cases are considered equal, regardless of what the
46+-- list of exceptions looks like.
21instance Eq a => Eq (Ok a) where
48instance Eq a => Eq (Ok a) where
22 Errors _ == Errors _ = True
49 Errors _ == Errors _ = True
23 Ok a == Ok b = a == b
50 Ok a == Ok b = a == b
@@ -37,7 +64,6 @@ instance Alternative Ok where
37 Errors _ <|> b@(Ok _) = b
64 Errors _ <|> b@(Ok _) = b
38 Errors as <|> Errors bs = Errors (as ++ bs)
65 Errors as <|> Errors bs = Errors (as ++ bs)
41instance MonadPlus Ok where
67instance MonadPlus Ok where
42 mzero = empty
68 mzero = empty
43 mplus = (<|>)
69 mplus = (<|>)
@@ -53,3 +79,10 @@ instance Monad Ok where
54 -- but *correct*, as this will throw an exception if you try to
80 -- but *correct*, as this will throw an exception if you try to
55 -- examine the exception.
81 -- examine the exception.
83+-- | a way to reify a list of exceptions into a single exception
85+newtype ManyErrors = ManyErrors [SomeException]
86+ deriving (Show, Typeable)
88+instance Exception ManyErrors