module Skulk.Outcome where
import Control.Applicative(liftA, Applicative,pure,(<$>),(<*>))
import Control.Monad(liftM,ap)
import Data.Foldable(Foldable,foldr)
import Data.Traversable(Traversable, sequenceA)
import Skulk.Deep
data Outcome a =
OK a
| Fail String
| Skip String
instance Eq a => Eq (Outcome a) where
(OK x) == (OK y) = x == y
(Fail x) == (Fail y) = x == y
(Skip x) == (Skip y) = x == y
_ == _ = False
instance Functor Outcome where
fmap f (OK x) = OK (f x)
fmap _ (Fail msg) = Fail msg
fmap _ (Skip msg) = Skip msg
instance Applicative Outcome where
pure = OK
(OK f) <*> ax = f <$> ax
(Fail msg) <*> _ = Fail msg
(Skip msg) <*> _ = Skip msg
instance Monad Outcome where
OK x >>= f = f x
Fail msg >>= _ = Fail msg
Skip msg >>= _ = Skip msg
return = OK
fail = Fail
instance Foldable Outcome where
foldr f x (OK y) = f y x
foldr _ x (Fail _) = x
foldr _ x (Skip _) = x
instance Traversable Outcome where
sequenceA (OK x) = liftA OK x
sequenceA (Fail msg) = pure $ Fail msg
sequenceA (Skip msg) = pure $ Skip msg
instance (Show a) => Show (Outcome a) where
show = describe show
describe :: (a -> String) -> Outcome a -> String
describe f (OK x) = f x
describe _ (Fail msg) = "FAIL: " ++ msg
describe _ (Skip msg) = "SKIP: " ++ msg
toEither :: Outcome a -> Either String a
toEither (OK x) = Right x
toEither (Fail msg) = Left $ "FAIL: " ++ msg
toEither (Skip msg) = Left $ "SKIP: " ++ msg
fromEither :: Either String a -> Outcome a
fromEither (Left msg) = Fail msg
fromEither (Right v) = OK v
fromMaybe :: String -> Maybe a -> Outcome a
fromMaybe msg = maybe (Fail msg) OK
allOK :: [Outcome a] -> Outcome [a]
allOK = impl []
where impl acc [] = OK $ reverse acc
impl acc (x:xs) = case x of
(OK y) -> impl (y:acc) xs
(Fail msg) -> Fail msg
(Skip _) -> impl acc xs
exposeOrDie :: Outcome a -> a
exposeOrDie = either error id . toEither
type OutcomeM a b = Deep a Outcome b
type OutcomeIO a = OutcomeM IO a
describeAndPrint :: (a -> String) -> OutcomeIO a -> IO ()
describeAndPrint f x = expose x >>= putStrLn . describe f