module Util.Computation (
Answer,
done,
( # ),
propagate,
try,
tryUntilOK,
raise,
when,
unless,
incase,
forever,
foreverUntil,
foreach,
while,
Config,
configure,
config,
HasConfig(..),
WithError,
hasError,
hasValue,
fromWithError,
fromWithError1,
toWithError,
isError,
mapWithError,
mapWithError',
mapWithErrorIO,
mapWithErrorIO',
pairWithError,
listWithError,
coerceWithError,
coerceWithErrorIO,
coerceWithErrorStringIO,
coerceWithErrorOrBreakIOPrefix,
coerceWithErrorOrBreakPrefix,
MonadWithError(..),
monadifyWithError,
toMonadWithError,
coerceWithErrorOrBreak,
coerceWithErrorOrBreakIO,
concatWithError,
swapIOWithError,
exceptionToError,
)
where
import Control.Monad
import Control.Exception
import Util.Debug(debug)
infixr 2 #
type Answer a = Either SomeException a
done :: Monad m => m ()
done = return ()
( # ) :: a -> (a -> b) -> b
o # f = f o
raise :: IOError -> IO a
raise e =
do
debug ("RAISED EXCP: " ++ (show e) ++ "\n")
ioError e
propagate :: Answer a -> IO a
propagate (Left e) = throw e
propagate (Right v) = return v
catchall :: IO a -> IO a -> IO a
catchall c1 c2 = Control.Exception.catch c1 (\ (_ :: SomeException) -> c2)
tryUntilOK :: IO a -> IO a
tryUntilOK c = catchall c (tryUntilOK c)
data WithError a =
Error String
| Value a
hasError :: String -> WithError a
hasError str = Error str
hasValue :: a -> WithError a
hasValue a = Value a
toWithError :: Either String a -> WithError a
toWithError (Left s) = Error s
toWithError (Right a) = Value a
isError :: WithError a -> Bool
isError (Error _) = True
isError (Value _) = False
fromWithError :: WithError a -> Either String a
fromWithError (Error s) = Left s
fromWithError (Value a) = Right a
fromWithError1 :: a -> WithError a -> a
fromWithError1 _ (Value a) = a
fromWithError1 a (Error _) = a
mapWithError :: (a -> b) -> WithError a -> WithError b
mapWithError f (Error e) = Error e
mapWithError f (Value x) = Value (f x)
mapWithError' :: (a -> WithError b) -> WithError a -> WithError b
mapWithError' f (Error e) = Error e
mapWithError' f (Value a) = f a
mapWithErrorIO :: (a -> IO b) -> WithError a -> IO (WithError b)
mapWithErrorIO f (Error e) = return (Error e)
mapWithErrorIO f (Value a) =
do
b <- f a
return (Value b)
mapWithErrorIO' :: (a -> IO (WithError b)) -> WithError a -> IO (WithError b)
mapWithErrorIO' f (Error e) = return (Error e)
mapWithErrorIO' f (Value a) = f a
pairWithError :: WithError a -> WithError b -> WithError (a,b)
pairWithError (Value a) (Value b) = Value (a,b)
pairWithError (Error e) (Value b) = Error e
pairWithError (Value a) (Error f) = Error f
pairWithError (Error e) (Error f) = Error (e++"\n"++f)
listWithError :: [WithError a] -> WithError [a]
listWithError awes =
foldr
(\ awe awes ->
mapWithError
(\ (a,as) -> a:as)
(pairWithError awe awes)
)
(hasValue [])
awes
coerceWithError :: WithError a -> a
coerceWithError (Value a) = a
coerceWithError (Error err) = error err
coerceWithErrorIO :: WithError a -> IO a
coerceWithErrorIO (Value a) = return a
coerceWithErrorIO (Error err) = error err
coerceWithErrorStringIO :: String -> WithError a -> IO a
coerceWithErrorStringIO _ (Value a) = return a
coerceWithErrorStringIO mess (Error err) =
error ("coerceWithErrorString " ++ mess ++ ": " ++ err)
coerceWithErrorOrBreakIO :: (String -> a) -> WithError a -> IO a
coerceWithErrorOrBreakIO = coerceWithErrorOrBreakIOPrefix ""
coerceWithErrorOrBreakIOPrefix
:: String -> (String -> a) -> WithError a -> IO a
coerceWithErrorOrBreakIOPrefix errorPrefix breakFn aWe =
do
let
a = coerceWithErrorOrBreakPrefix errorPrefix breakFn aWe
seq a (return a)
coerceWithErrorOrBreak :: (String -> a) -> WithError a -> a
coerceWithErrorOrBreak = coerceWithErrorOrBreakPrefix ""
coerceWithErrorOrBreakPrefix :: String -> (String -> a) -> WithError a -> a
coerceWithErrorOrBreakPrefix errorPrefix breakFn (Value a) = a
coerceWithErrorOrBreakPrefix errorPrefix breakFn (Error s)
= breakFn (errorPrefix ++ s)
concatWithError :: [WithError a] -> WithError [a]
concatWithError withErrors =
foldr
(\ wE wEsf -> mapWithError (uncurry (:)) (pairWithError wE wEsf))
(Value [])
withErrors
swapIOWithError :: WithError (IO a) -> IO (WithError a)
swapIOWithError (Error e) = return (Error e)
swapIOWithError (Value act) =
do
v <- act
return (Value v)
exceptionToError :: Exception e => (e -> Maybe String) -> IO a -> IO (WithError a)
exceptionToError testFn action =
catchJust
testFn
(do
val <- action
return (hasValue val)
)
(\ str -> return (hasError str))
instance Functor WithError where
fmap aToB aWE = case aWE of
Value a -> Value (aToB a)
Error e -> Error e
instance Monad WithError where
return v = hasValue v
(>>=) aWE toBWe =
mapWithError' toBWe aWE
fail s = hasError s
newtype MonadWithError m a = MonadWithError (m (WithError a))
instance Monad m => Monad (MonadWithError m) where
return v = MonadWithError (return (Value v))
(>>=) (MonadWithError act1) getAct2 =
MonadWithError (
do
valWithError <- act1
case valWithError of
Value v ->
let
(MonadWithError act2) = getAct2 v
in
act2
Error s -> return (Error s)
)
fail s = MonadWithError (return (Error s))
monadifyWithError :: Monad m => WithError a -> MonadWithError m a
monadifyWithError we = MonadWithError (return we)
toMonadWithError :: Monad m => m a -> MonadWithError m a
toMonadWithError act = MonadWithError (
do
a <- act
return (hasValue a)
)
foreverUntil :: Monad m => m Bool -> m ()
foreverUntil act =
do
stop <- act
if stop
then
done
else
foreverUntil act
foreach :: Monad m => [a] -> (a -> m b) -> m ()
foreach el c = sequence_ (map c el)
incase :: Maybe a -> (a -> IO b) -> IO ()
incase Nothing f = done
incase (Just a) f = do {f a; done}
while :: Monad m => m a -> (a -> Bool) -> m a
while c p = c >>= \x -> if (p x) then while c p else return x
type Config w = w -> IO w
configure :: w -> [Config w] -> IO w
configure w [] = return w
configure w (c:cl) = do {w' <- c w; configure w' cl}
config :: IO () -> Config w
config f w = f >> return w
class HasConfig option configuration where
($$) :: option -> configuration -> configuration
configUsed :: option -> configuration -> Bool
infixr 0 $$