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.

+2


a source to share


3 answers


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

.

+7


a source


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 "")

      

+3


a source


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.

+1


a source







All Articles