module Control.Applicative.Fail
( Fail(..)
, ffail
, fwarn
, fsucc
, getFail
, getSucc
, failEither
, joinFail
, bindFail
, composeFail
) where
import Control.Applicative
import Data.Bifunctor
import Data.Foldable
import Data.Monoid
import Data.Traversable
import Data.Typeable
import GHC.Generics
data Fail e a
= Fail e (Maybe a)
| Success a
deriving ( Eq, Ord, Show, Read, Functor
, Foldable, Traversable
, Typeable, Generic )
instance Bifunctor Fail where
bimap fe fa (Fail e a) = Fail (fe e) (fa <$> a)
bimap _ fa (Success a) = Success (fa a)
instance (Monoid e) => Applicative (Fail e) where
pure a = Success a
(Success f) <*> a = fmap f a
(Fail e1 f) <*> (Fail e2 a) = Fail (e1 <> e2) (f <*> a)
(Fail e f) <*> (Success a) = Fail e (fmap ($ a) f)
instance (Monoid e, Monoid a) => Monoid (Fail e a) where
mempty = Success mempty
mappend (Success a) (Success b) = Success $ a <> b
mappend (Fail e1 a) (Fail e2 b) = Fail (e1 <> e2) (mappend <$> a <*> b)
mappend res@(Fail{}) (Success{}) = res
mappend (Success{}) res@(Fail{}) = res
ffail :: e -> Fail [e] a
ffail e = Fail (pure e) Nothing
fwarn :: e -> a -> Fail [e] a
fwarn e a = Fail [e] (Just a)
fsucc :: a -> Fail e a
fsucc a = Success a
failEither :: Fail e a -> Either e a
failEither (Success a) = Right a
failEither (Fail e _) = Left e
getFail :: Fail e a -> Maybe e
getFail (Fail e _) = Just e
getFail _ = Nothing
getSucc :: Fail e a -> Maybe a
getSucc (Success a) = Just a
getSucc (Fail _ a) = a
joinFail :: (Monoid e)
=> Fail e (Fail e a)
-> Fail e a
joinFail (Success a) = a
joinFail (Fail e a) =
let ee = maybe e (e <>)
(a >>= getFail)
aa = a >>= getSucc
in Fail ee aa
bindFail :: (Monoid e)
=> Fail e a
-> (a -> Fail e b)
-> Fail e b
bindFail a f = joinFail $ fmap f a
infixl 1 `bindFail`
composeFail :: (Monoid e)
=> (a -> Fail e b)
-> (b -> Fail e c)
-> a
-> Fail e c
composeFail l r a = bindFail (l a) r
infixl 1 `composeFail`