Haskell: Working with Types and Exceptions
I would like to know the "Haskell way" to catch and handle exceptions. As shown below, I understand the basic syntax, but I'm not sure how to deal with the type system in this situation.
The code below tries to return the value of the requested environment variable. Obviously, if this variable is not there, I want to catch the exception and return Nothing.
getEnvVar x = do {
var <- getEnv x;
Just var;
} `catch` \ex -> do {
Nothing
}
Here is the error:
Couldn't match expected type `IO a'
against inferred type `Maybe String'
In the expression: Just var
In the first argument of `catch', namely
`do { var <- getEnv x;
Just var }'
In the expression:
do { var <- getEnv x;
Just var }
`catch`
\ ex -> do { Nothing }
I can return string values:
getEnvVar x = do {
var <- getEnv x;
return var;
} `catch` \ex -> do {
""
}
however, this doesn't sound like the Haskell way. What is Haskell?
Edit: Updated code to reflect the description correctly.
a source to share
You cannot undo IO
and redo Maybe String
inside a do block. You need to return IO (Maybe String)
.
getEnvVar x = do {
var <- getEnv x;
return (Just var);
} `catch` \ex -> do {
return Nothing
}
Why not use
import qualified System.IO.Error as E
getEnvVar :: String -> IO (Either IOError String)
getEnvVar = E.try . getEnv
Instead of Nothing
and, Just var
you get Left error
and Right var
.
a source to share
Once you get that everything related to getEnv
is related to returning a result in a monad IO
, then there is nothing wrong with your basic approach. And while you could System.IO.Error
(and I would), it is just as correct and instructive to write the way you did. However, you used a little more punctuation than using idomatic Haskell:
getEnvVar x = (Just `fmap` getEnv x) `catch` const (return Nothing)
or
getEnvVar x = getEnv x `catch` const (return "")
a source to share
You can also try
import System.Environment
getEnvVar :: String -> IO (Maybe String)
getEnvVar x = getEnvironment >>= return . lookup x
or a little longer, but it might be easier to follow:
getEnvVar x = do
fullEnvironment <- getEnvironment
return (lookup x fullEnvironment)
if you don't mind going through the whole environment all the time.
a source to share