如何将IO ByteString转换为IO String

时间:2015-01-15 19:32:29

标签: haskell

我知道如何使用unpack将ByteString转换为String,但我正在努力弄清楚如何将IO ByteString(这是我从HaskellNet中的fetchHeader函数返回的内容)转换为IO String。我基本上试图做这样的事情

getAllHeadersForMessageUID :: IMapConnection -> UID -> IO String
getAllHeadersForMessageUID connection uid = do
   headers <- fetchHeader connection uid  
   return (headers  >>= BS.unpack)

错误消息对我没有意义

Couldn't match expected type ‘[BS.ByteString]’
            with actual type ‘BS.ByteString’
In the first argument of ‘(>>=)’, namely ‘headers’
In the first argument of ‘return’, namely ‘(headers >>= BS.unpack)

我不知道为什么会出现ByteString列表。

2 个答案:

答案 0 :(得分:8)

尝试使用return $ BS.unpack headers代替return (headers >>= BS.unpack)

如果标题是ByteStrings列表,请尝试return $ map BS.unpack headers

除了碰巧输入类型检查(我假设BS.unpack headers有效),这是一种思考问题的方法:

  • headers是纯值
  • BS.unpack是纯函数
  • headers >>= ...没有意义,因为>>=的LHS需要是monadic计算
  • ... >>= BS.unpack没有意义,因为>>=的RHS需要是一个产生monadic计算的函数
  • BS.unpack headers是我们想要返回的字符串,但它是一个纯值
  • 因此我们使用return将纯值提升为monadic计算

更新

以下代码显示,如果fetchHeader的类型为IO [BS.ByteString],那么您的代码将输入check:

import Data.ByteString.Char8 as BS

fetchHeader :: IO [BS.ByteString]   -- this works
-- fetchHeader :: IO BS.ByteString  -- this doesn't
fetchHeader = undefined

foo :: IO String
foo = do
  headers <- fetchHeader
  return $ headers >>= BS.unpack

另一方面,如果您将其类型更改为IO BS.ByteString,则会收到您遇到的错误。

更新2

有趣的是,当headers是ByteStrings列表时,表达式headers >>= BS.unpack确实有意义并且相当于:

concat $ map BS.unpack headers

答案 1 :(得分:0)

User5402的回答假设ByteString是纯ASCII(如果你是唯一一个使用你代码的人,那就没关系,但是如果你打算分享它,有几个原因可能是个坏主意) 如果ByteString使用UTF-8编码:您可以将其转换为String,如下所示:

import qualified Codec.Binary.UTF8.String as UTF8
foo b = do
  bs <- b
  return $ UTF8.decode $ unpack bs

我不确定如何处理其他编码,例如Windows代码页(除了设置句柄的编码,这不适用于此处)。