我是 Haskell 的新手,正在尝试 http-conduit 版本 2.0.0.4 的示例代码,但它不起作用
这里是示例代码
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Conduit
import Network
import Data.Time.Clock
import Data.Time.Calendar
import qualified Control.Exception as E
past :: UTCTime
past = UTCTime (ModifiedJulianDay 56200) (secondsToDiffTime 0)
future :: UTCTime
future = UTCTime (ModifiedJulianDay 562000) (secondsToDiffTime 0)
cookie :: Cookie
cookie = Cookie { cookie_name = "password_hash"
, cookie_value = "abf472c35f8297fbcabf2911230001234fd2"
, cookie_expiry_time = future
, cookie_domain = "example.com"
, cookie_path = "/"
, cookie_creation_time = past
, cookie_last_access_time = past
, cookie_persistent = False
, cookie_host_only = False
, cookie_secure_only = False
, cookie_http_only = False
}
main = withSocketsDo $ do
request' <- parseUrl "http://example.com/secret-page"
let request = request' { cookieJar = Just $ createCookieJar [cookie] }
E.catch (withManager $ httpLbs request)
(\(StatusCodeException statusCode _ _) ->
if statusCode==403 then putStrLn "login failed" else return ())
引用:http://hackage.haskell.org/package/http-conduit-2.0.0.4/docs/Network-HTTP-Conduit.html
加载时的错误信息
samplecode.hs:33:39:
Couldn't match type `()'
with `Response Data.ByteString.Lazy.Internal.ByteString'
Expected type: IO
(Response Data.ByteString.Lazy.Internal.ByteString)
Actual type: IO ()
In the return type of a call of `putStrLn'
In the expression: putStrLn "login failed"
In the expression:
if statusCode == 403 then putStrLn "login failed" else return ()
samplecode.hs:33:75:
Couldn't match expected type `Response
Data.ByteString.Lazy.Internal.ByteString'
with actual type `()'
In the first argument of `return', namely `()'
In the expression: return ()
In the expression:
if statusCode == 403 then putStrLn "login failed" else return ()
Failed, modules loaded: none.
我该如何解决?
非常感谢
更新
按照 Abrahamson 的建议,我将我的代码稍微更改为以下内容,现在可以正确处理 StatusCodeException。
main = withSocketsDo $ do
request' <- parseUrl "http://example.com/secret-page"
let request = request' { cookieJar = Just $ createCookieJar [cookie] }
eitherResp <- E.try (withManager $ httpLbs request)
case eitherResp of
Left (StatusCodeException s _ _)
| statusCode s == 403 -> putStrLn "login failed"
| otherwise -> return ()
Right resp -> print (L.length (responseBody resp))
最佳答案
您没有按预期使用 E.catch
。如果你看一下类型:
E.catch :: Exception e => IO a -> (e -> IO a) -> IO a
很明显,第一个和第二个参数的返回类型必须匹配。在你的情况下你有
withManager $ httpLbs request :: IO (Response ByteString)
在第一个分支和任一个
putStrLn "login failed" -- or
return ()
在第二个。这些类型不匹配,因此您会看到错误。
在更高层次上,问题在于您没有处理成功案例。例如,我们可以使用 E.try
重写它以使其更清晰
eitherResp <- E.try (withManager $ httpLbs request)
case eitherResp of
Left (StatusCodeException statusCode _ _)
| statusCode == 403 -> putStrLn "login failed"
| otherwise -> return ()
Right resp -> print (ByteString.length (responseBody resp))
这里因为我在 Either StatusCodeException (Response ByteString)
上进行了显式模式匹配,所以很明显我需要提供失败和后续分支并为它们提供相同的返回类型。为此,我引入了对成功案例执行的操作。
一般来说,我发现 E.try
更容易使用。 E.catch
主要用于在失败时提供默认值。
关于haskell - 执行http-conduit 2.0.0.4版本的示例代码时如何修复错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21385142/