Reputation: 34874
Could anyone explain why can't I do this:
getHeaders :: String -> IO ResponseHeaders
getHeaders url = parseUrl url >>= withManager . httpLbs >>= responseHeaders
--getHeaders url = parseUrl url >>= (\x -> withManager $ httpLbs x) >>= responseHeaders -- doesn't compiler either
and have to do this instead:
getHeaders url = do
req <- parseUrl url
res <- withManager $ httpLbs req
return $ responseHeaders res
due to the error:
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
And is there any way to make it work with >>=
, not do
?
update:
Indeed, adding return makes it work. However, I don't understand why I can chain them as they have different types of Monads. As far as I am concerned, they can't be chained with >>=
because the return type of the left expression is not the same as the input the right expression accepts. Look:
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
Upvotes: 0
Views: 214
Reputation: 11963
You forgot the return in your translation using >>=
. The correct code is:
getHeaders url = parseUrl url >>= withManager . httpLbs >>= return . responseHeaders
This is required because (>>=) :: IO a -> (a -> IO b) -> IO b
, but in your case, responseHeaders
gives back a value of type ResponseHeaders
, which doesn't match the IO b
. With the return, you "lift" that value in the IO monad, so you get IO ResponseHeaders
and the types match.
But, because a >>= return . f
is equal to fmap f a
for all f
and a
, this can also be written as:
parseUrl url = fmap responseHeaders $ parseUrl url >>= withManager . httpLbs
Upvotes: 7
Reputation: 144106
responseHeaders
returns ResponseHeaders
while you need to return an IO responseHeaders
from the last call to >>=
.
You can use:
getHeaders url = parseUrl url >>= withManager . httpLbs >>= (return . responseHeaders)
Upvotes: 1