packages feed

monadology-0.4: src/Control/Monad/Ology/Specific/Result.hs

module Control.Monad.Ology.Specific.Result where

import Import

data Result e a
    = SuccessResult a
    | FailureResult e

resultToMaybe :: Result e a -> Maybe a
resultToMaybe (SuccessResult a) = Just a
resultToMaybe _ = Nothing

resultToM :: MonadFail m => Result String a -> m a
resultToM (SuccessResult a) = return a
resultToM (FailureResult e) = fail e

resultToEither :: Result e a -> Either e a
resultToEither (FailureResult e) = Left e
resultToEither (SuccessResult a) = Right a

eitherToResult :: Either e a -> Result e a
eitherToResult (Left e) = FailureResult e
eitherToResult (Right a) = SuccessResult a

resultFromMaybe :: e -> Maybe a -> Result e a
resultFromMaybe _ (Just a) = SuccessResult a
resultFromMaybe e Nothing = FailureResult e

maybeToM :: MonadFail m => String -> Maybe a -> m a
maybeToM e = resultToM . resultFromMaybe e

deriving stock instance (Eq e, Eq a) => Eq (Result e a)

instance Functor (Result e) where
    fmap ab (SuccessResult a) = SuccessResult (ab a)
    fmap _ (FailureResult e) = FailureResult e

instance Foldable (Result e) where
    foldMap am (SuccessResult a) = am a
    foldMap _ (FailureResult _) = mempty

instance Traversable (Result e) where
    traverse afb (SuccessResult a) = fmap SuccessResult (afb a)
    traverse _ (FailureResult e) = pure (FailureResult e)
    sequenceA (SuccessResult fa) = fmap SuccessResult fa
    sequenceA (FailureResult e) = pure (FailureResult e)

instance Applicative (Result e) where
    pure = SuccessResult
    (SuccessResult ab) <*> (SuccessResult a) = SuccessResult (ab a)
    (SuccessResult _) <*> (FailureResult e) = FailureResult e
    (FailureResult e) <*> _ = FailureResult e

instance Monad (Result e) where
    (FailureResult e) >>= _ = FailureResult e
    (SuccessResult a) >>= amq = amq a

instance IsString e => MonadFail (Result e) where
    fail s = FailureResult $ fromString s

instance Monoid e => Alternative (Result e) where
    empty = FailureResult mempty
    (SuccessResult a) <|> _ = SuccessResult a
    (FailureResult _) <|> (SuccessResult a) = SuccessResult a
    (FailureResult e1) <|> (FailureResult e2) = FailureResult $ mappend e1 e2

instance Monoid e => MonadPlus (Result e)

instance MonadFix (Result e) where
    mfix ama = let
        getSuccess (SuccessResult a) = a
        getSuccess (FailureResult _) = error "mfix FailureResult"
        ma = ama $ getSuccess ma
        in ma

instance (Show e, Show a) => Show (Result e a) where
    show (SuccessResult a) = "success: " ++ show a
    show (FailureResult e) = "failure: " ++ show e

mapResultFailure :: (e1 -> e2) -> Result e1 a -> Result e2 a
mapResultFailure _ (SuccessResult a) = SuccessResult a
mapResultFailure e1e2 (FailureResult e1) = FailureResult (e1e2 e1)