Yet another monad transformer or silly usage of Either?
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? Or may be there's some trick available for Either? I looked at EitherT, and it seems that I have to wrap every invocation into EitherT and then chain them with >>/>>= -- Eugene Dzhurinsky
Yeah, ErrorT should do what you want (EitherT is probably essentially the same thing) login would have the type: login :: String -> String -> ErrorT DServError IO LoginResponse and you would use it like this: result <- runErrorT $ authenticatedReq You can use runErrorT, or catch when you want to process a possible error. result would have the type Either DServError whatever. This would leave out the Result type, but if you really want to, you can add it with the appropriate lifting. Hope that helps, - Job 2010/7/25 Eugeny N Dzhurinsky <bofh@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? Or may be there's some trick available for Either?
I looked at EitherT, and it seems that I have to wrap every invocation into EitherT and then chain them with >>/>>=
-- Eugene Dzhurinsky
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
2010/7/25 Eugeny N Dzhurinsky <bofh@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 <dave@zednenem.com> <http://www.eyrie.org/~zednenem/>
participants (3)
-
David Menendez -
Eugeny N Dzhurinsky -
Job Vranish