不能为IO monad链接函数,而是要用“do”代替

时间:2014-07-11 14:52:52

标签: haskell

有人可以解释为什么我不能这样做:

getHeaders :: String -> IO ResponseHeaders
getHeaders url = parseUrl url >>= withManager . httpLbs >>= responseHeaders
--getHeaders url = parseUrl url >>= (\x -> withManager $ httpLbs x) >>= responseHeaders -- doesn't compiler either

并且必须这样做:

getHeaders url = do
  req <- parseUrl url
  res <- withManager $ httpLbs req
  return $ responseHeaders res

由于错误:

Couldn't match type `[]' with `IO'
    Expected type: Response Data.ByteString.Lazy.Internal.ByteString
                   -> IO ResponseHeaders
      Actual type: Response Data.ByteString.Lazy.Internal.ByteString
                   -> ResponseHeaders
    In the second argument of `(>>=)', namely `responseHeaders'
    In the expression:
      parseUrl url >>= withManager . httpLbs >>= responseHeaders

有没有办法让它与>>=合作,而不是do

更新

确实,添加返回会使其有效。但是,我不明白为什么我可以链接它们,因为它们有不同类型的Monads。就我而言,它们不能与>>=链接,因为左表达式的返回类型与右表达式接受的输入不同。看:

http://hackage.haskell.org/package/http-conduit-1.2.4/docs/Network-HTTP-Conduit.html#v:parseUrl

parseUrl :: Failure HttpException m => String -> m (Request m')

withManager :: ResourceIO m => (Manager -> ResourceT m a) -> m a

2 个答案:

答案 0 :(得分:7)

您使用>>=忘记了翻译中的回复。正确的代码是:

getHeaders url = parseUrl url >>= withManager . httpLbs >>= return . responseHeaders

这是必需的,因为(>>=) :: IO a -> (a -> IO b) -> IO b,但在您的情况下,responseHeaders会返回ResponseHeaders类型的值,该值与IO b不匹配。通过回归,你可以解除&#34; IO monad中的值,因此您得到IO ResponseHeaders且类型匹配。

但是,因为a >>= return . f对于所有fmap f af等于a,所以这也可以写成:

parseUrl url = fmap responseHeaders $ parseUrl url >>= withManager . httpLbs

答案 1 :(得分:1)

responseHeaders返回ResponseHeaders,同时您需要在上次拨打IO responseHeaders时返回>>=

您可以使用:

getHeaders url = parseUrl url >>= withManager . httpLbs >>= (return . responseHeaders)