2010-04-21 57 views
2

我想知道「Haskell方式」來捕獲和處理異常。如下所示,我理解基本語法,但我不確定在這種情況下如何處理類型系統。Haskell:處理類型和異常

下面的代碼嘗試返回請求的環境變量的值。顯然,如果該變量不在那裏,我想捕獲異常並返回Nothing。

getEnvVar x = do { 
    var <- getEnv x; 
    Just var; 
} `catch` \ex -> do { 
    Nothing 
} 

以下是錯誤:

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 } 

我可以返回字符串值:

getEnvVar x = do { 
    var <- getEnv x; 
    return var; 
} `catch` \ex -> do { 
    "" 
} 

然而,這種感覺並不像Haskell的方式。什麼是Haskell方式?

編輯:更新了代碼以正確反映描述。

回答

7

您不能剝離IO並在do-block內返回Maybe String。您需要退回IO (Maybe String)

getEnvVar x = do { 
    var <- getEnv x; 
    return (Just var); 
} `catch` \ex -> do { 
    return Nothing 
} 

爲什麼不使用

import qualified System.IO.Error as E 
getEnvVar :: String -> IO (Either IOError String) 
getEnvVar = E.try . getEnv 

代替NothingJust var,你會得到Left errorRight var

1

您也可以嘗試

import System.Environment 
getEnvVar :: String -> IO (Maybe String) 
getEnvVar x = getEnvironment >>= return . lookup x 

或者時間長一點,但也許更容易理解:

getEnvVar x = do 
    fullEnvironment <- getEnvironment 
    return (lookup x fullEnvironment) 

,如果你不介意在整個環境中去的全部時間。

+1

有沒有必要使用此單子的力量; 'getEnvVar x = fmap(lookup x)getEnvironment'工作得很好,並且需要使用'return' – Warbo 2015-08-01 08:24:30

3

一旦你得到什麼涉及getEnv將涉及返回結果在IO monad,那麼你的基本方法沒有任何問題。雖然你可以使用System.IO.Error(而且我會),但按照你的方式寫它也是一樣有效和有益的。但是,你沒有使用更多的標點符號比idomatic哈斯克爾將使用:

getEnvVar x = (Just `fmap` getEnv x) `catch` const (return Nothing) 

getEnvVar x = getEnv x `catch` const (return "")