Haskell类型抛出意外异常

时间:2014-08-21 20:30:22

标签: haskell exception-handling

我正在查询远程API并遇到了一个问题,当我不希望它发生异常时会抛出异常。我已经检查了类型,似乎没有问题将我需要的值绑定到变量上。

我将Network.HTTP.Client别名HTTPClientimport qualified Data.ByteString.Lazy as LBS别名LBS

这是我的GHCi会话的样子:

λ> manager <- HTTPClient.newManager HTTPClient.defaultManagerSettings
λ> request <- HTTPClient.parseUrl postsURL
λ> :t HTTPClient.httpLbs request manager
HTTPClient.httpLbs request manager
  :: IO (HTTPClient.Response LBS.ByteString)
λ> response <- HTTPClient.httpLbs request manager
*** Exception: StatusCodeException (Status {statusCode = 403, statusMessage = "Forbidden"}) [("Date","Thu, 21 Aug 2014 20:25:15 GMT"),("Server","Apache/2.2.22 (Ubuntu)"),("Vary","Accept-Encoding"),("Content-Encoding","gzip"),("Content-Length","239"),("Content-Type","text/html; charset=iso-8859-1"),("X-Response-Body-Start","<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>403 Forbidden</title>\n</head><body>\n<h1>Forbidden</h1>\n<p>You don't have permission to access /posts/all\non this server.</p>\n<hr>\n<address>Apache/2.2.22 (Ubuntu) Server at api.pinboard.in Port 80</address>\n</body></html>\n"),("X-Request-URL","GET http://api.pinboard.in:80/posts/all?format=json&auth_token=username:XXXXX")] (CJ {expose = []})

然后,当然:

λ> response

<interactive>:14:1: Not in scope: `response'

我会认为我可以将httpLbs的结果绑定到响应中,因为它包含在IO monad中,但似乎某种方式引发的异常会阻止这种情况发生。我认为类型应该可以防止这样的情况,但也许我做错了。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:4)

作为您的起点,让我为您举一个实例:

import           Network.HTTP.Conduit
import qualified Control.Exception as E
import           Network.HTTP.Types.Status
import           Data.ByteString.Lazy.Char8 (pack)

main :: IO ()
main = do
  let url = "http://www.google.com/does-not-exist.txt"
  res <- (simpleHttp url) `E.catch`
        (\(StatusCodeException s _ _) -> (return . pack . show . statusCode $ s))
  print res

在ghci:

λ> main
"404"

在上面的示例中,我从异常中恢复状态代码404。您可以按照相同的方法为Exception执行自定义逻辑处理。

更新:使用httpLbs的方法:

根据forum的建议,您可以将Maybe包裹在Response之上并执行异常处理:

import Network.HTTP.Client
import qualified Control.Exception as E
import Network.HTTP.Types.Status (statusCode)

main = do
  manager <- newManager defaultManagerSettings
  request <- parseUrl "http://www.google.com/does-not-exist.txt"
  resp <- (fmap Just $ httpLbs request manager) `E.catch` handleMyException
  print resp

handleMyException :: HttpException -> IO (Maybe a)
handleMyException (StatusCodeException s _ _) = if statusCode s == 404
                                                then putStrLn ((show . statusCode $ s) ++ " I'm sorry!") >> return Nothing
                                                else return Nothing

示例演示:

λ> main
404 I'm sorry!
Nothing

  

我认为类型应该可以防止这样的情况,   但也许我做错了什么。

与现实世界交流时,类型无法保护您。执行IO活动(如读取文件,连接到套接字等)取决于许多外部因素,这些因素不受Haskell(或任何PL)的控制。因此,当这样的事情失败时,Haskell无能为力。但好处是,Haskell明确指出那些IO动作表明你已经脱离了纯粹的领域。