X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/25779212dca36503765c2353da08cd659b0ca8de..b90974684da8e881ad8a54b9368896439a984a97:/htools/Ganeti/BasicTypes.hs diff --git a/htools/Ganeti/BasicTypes.hs b/htools/Ganeti/BasicTypes.hs index 61a7e56..149540f 100644 --- a/htools/Ganeti/BasicTypes.hs +++ b/htools/Ganeti/BasicTypes.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE FlexibleInstances #-} + {- Copyright (C) 2009, 2010, 2011, 2012 Google Inc. @@ -20,7 +22,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -} module Ganeti.BasicTypes - ( Result(..) + ( GenericResult(..) + , Result + , ResultT(..) + , resultT + , FromString(..) , isOk , isBad , eitherToResult @@ -38,30 +44,40 @@ module Ganeti.BasicTypes import Control.Applicative import Control.Monad +import Control.Monad.Trans import Data.Function import Data.List --- | This is similar to the JSON library Result type - /very/ similar, --- but we want to use it in multiple places, so we abstract it into a --- mini-library here. --- --- The failure value for this monad is simply a string. -data Result a - = Bad String - | Ok a +-- | Generic monad for our error handling mechanisms. +data GenericResult a b + = Bad a + | Ok b deriving (Show, Read, Eq) -instance Monad Result where +-- | Type alias for a string Result. +type Result = GenericResult String + +-- | Type class for things that can be built from strings. +class FromString a where + mkFromString :: String -> a + +-- | Trivial 'String' instance; requires FlexibleInstances extension +-- though. +instance FromString [Char] where + mkFromString = id + +-- | 'Monad' instance for 'GenericResult'. +instance (FromString a) => Monad (GenericResult a) where (>>=) (Bad x) _ = Bad x (>>=) (Ok x) fn = fn x return = Ok - fail = Bad + fail = Bad . mkFromString -instance Functor Result where +instance Functor (GenericResult a) where fmap _ (Bad msg) = Bad msg fmap fn (Ok val) = Ok (fn val) -instance MonadPlus Result where +instance MonadPlus (GenericResult String) where mzero = Bad "zero Result when used as MonadPlus" -- for mplus, when we 'add' two Bad values, we concatenate their -- error descriptions @@ -69,25 +85,48 @@ instance MonadPlus Result where (Bad _) `mplus` x = x x@(Ok _) `mplus` _ = x -instance Applicative Result where +instance Applicative (GenericResult a) where pure = Ok (Bad f) <*> _ = Bad f _ <*> (Bad x) = Bad x (Ok f) <*> (Ok x) = Ok $ f x --- | Simple checker for whether a 'Result' is OK. -isOk :: Result a -> Bool +-- | This is a monad transformation for Result. It's implementation is +-- based on the implementations of MaybeT and ErrorT. +newtype ResultT a m b = ResultT {runResultT :: m (GenericResult a b)} + +instance (Monad m, FromString a) => Monad (ResultT a m) where + fail err = ResultT (return . Bad $ mkFromString err) + return = lift . return + x >>= f = ResultT $ do + a <- runResultT x + case a of + Ok val -> runResultT $ f val + Bad err -> return $ Bad err + +instance MonadTrans (ResultT a) where + lift x = ResultT (liftM Ok x) + +instance (MonadIO m, FromString a) => MonadIO (ResultT a m) where + liftIO = lift . liftIO + +-- | Lift a `Result` value to a `ResultT`. +resultT :: Monad m => GenericResult a b -> ResultT a m b +resultT = ResultT . return + +-- | Simple checker for whether a 'GenericResult' is OK. +isOk :: GenericResult a b -> Bool isOk (Ok _) = True -isOk _ = False +isOk _ = False --- | Simple checker for whether a 'Result' is a failure. -isBad :: Result a -> Bool +-- | Simple checker for whether a 'GenericResult' is a failure. +isBad :: GenericResult a b -> Bool isBad = not . isOk --- | Converter from Either String to 'Result'. -eitherToResult :: Either String a -> Result a -eitherToResult (Left s) = Bad s -eitherToResult (Right v) = Ok v +-- | Converter from Either to 'GenericResult'. +eitherToResult :: Either a b -> GenericResult a b +eitherToResult (Left s) = Bad s +eitherToResult (Right v) = Ok v -- | Annotate a Result with an ownership information. annotateResult :: String -> Result a -> Result a