2010/7/25 Eugeny N Dzhurinsky <b...@redwerk.com>:
> Hello, everybody!
>
> I am trying to develop some sort of library, which supposed to sign into a WEB
> service, then perform some requests with it.
>
> Initially I designed methods in the following way
>
> data DServError = InvalidCredentials | InvalidRequest | ...
>
> newtype Result a = Result { getOpResult :: Either DServError a }
>
> data DSession = Session { ... }
>
> data DLoginResponse = LoginResponse { currentSession :: DSession, ... }
>
> login :: String -> String -> IO ( Result LoginResponse )
>
> servRequest1 :: DSession -> ParamType1 -> ParamType2 -> ... -> IO ( Result 
> DServResponse )
>
>
> Now I want to be able of doing something like
>
> authenticatedReq = do
>    loginResponse <- login "username" "password"
>    let session = currentSession loginResponse
>    servRequest1 session ... ... ...
>    servRequest2 session ... ... ...
>    ...
>
> so if login succeeds - I will be able to extract Right data from the Either 
> response ( with
> explicit or implicit usage of getOpResult), if any of operations within "do"
> block will fail with DServError - then an error should be reported.
>
> I think the solution for this may be using Control.Exception and it's
> try/catch?

That would work. If all of your operations require IO, you may as well
use IO for exceptions. It really depends on how explicit you want to
be about the varieties of exceptions your code may throw.

The documentation for Control.Exception has a pretty good explanation
of how to define instances for Exception.

e.g.,

data DServError = InvalidCredentials | ... deriving (Show, Typeable)

instance Exception DServError DServError

login :: String -> String -> IO LoginResponse
servRequest1 :: DSession -> ParamType1 -> ... -> IO DServResponse


It may be a better choice to make each exception its own type, and
possibly create a sub-heirarchy. E.g.,

data DServError = forall a. (Exception a) => DServError a deriving (Typeable)

instance Show DServError where show (DServError a) = show a

dServErrorToException :: Exception a => a -> SomeException
dServErrorToException = toException . DServError

dServErrorFromException :: Exception a => SomeException -> Maybe a
dServErrorFromException x = fromException x >>= \(DServError a) -> cast a

data InvalidCredentials deriving (Show, Typeable)

instance Exeption InvalidCredentials where
    toException = dServErrorToException
    fromException = dServErrorFromException

data InvalidRequest deriving (Show, Typeable)

instance Exeption InvalidRequest where
    toException = dServErrorToException
    fromException = dServErrorFromException

etc.

This allows you to write "m `catch` \(e :: DServError) -> ..." and "m
`catch` \InvalidCredentials -> ..." without worrying about
pattern-match errors.

-- 
Dave Menendez <d...@zednenem.com>
<http://www.eyrie.org/~zednenem/>
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to