{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor      #-}

module Database.PostgreSQL.Simple.Ok where

import Control.Applicative
import Control.Exception
import Control.Monad(MonadPlus(..))
import Data.Typeable

newtype ManyErrors = ManyErrors [SomeException] 
   deriving (Show, Typeable)

instance Exception ManyErrors

-- FIXME:   [SomeException] should probably be a difference list

data Ok a = Errors [SomeException] | Ok !a
    deriving(Show, Typeable, Functor)

instance Eq a => Eq (Ok a) where
    Errors _ == Errors _  = True
    Ok  a    == Ok  b     = a == b
    _        == _         = False

instance Applicative Ok where
    pure = Ok

    Errors es <*> _ = Errors es
    _ <*> Errors es = Errors es
    Ok f <*> Ok a   = Ok (f a)

instance Alternative Ok where
    empty = Errors []

    a@(Ok _)  <|> _         = a
    Errors _  <|> b@(Ok _)  = b
    Errors as <|> Errors bs = Errors (as ++ bs)


instance MonadPlus Ok where
    mzero = empty
    mplus = (<|>)

instance Monad Ok where
    return = Ok

    Errors es >>= _ = Errors es
    Ok a      >>= f = f a
    -- TODO:  add a definition for "fail",  akin to

    -- fail str = Errors [SomeException (error str)]

    -- but *correct*,  as this will throw an exception if you try to
    -- examine the exception.