如何将 IO ByteString 转换为 IO String
How can I convert IO ByteString to IO String
我知道如何通过解包将 ByteString 转换为 String,但我正在努力弄清楚如何将 IO ByteString(这是我从 HaskellNet 中的 fetchHeader 函数返回的)转换为 IO 字符串。我基本上是想做这样的事情
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 列表。
尝试使用 return $ BS.unpack headers
而不是 return (headers >>= BS.unpack)
。
或者尝试 return $ map BS.unpack headers
如果 headers 是一个 ByteString 列表。
除了它碰巧会进行类型检查(我假设 BS.unpack headers
有效)之外,还有一种思考方式:
headers
是纯值
BS.unpack
是纯函数
headers >>= ...
没有意义,因为 >>=
的 LHS 需要是一元计算
... >>= BS.unpack
没有意义,因为 >>=
的 RHS 需要是一个产生单子计算的函数
BS.unpack headers
是我们要的字符串return,但是是一个纯值
- 因此我们使用
return
将纯值提升为一元计算
更新:
以下代码表明,如果 fetchHeader
的类型为 IO [BS.ByteString]
,那么您的代码将进行类型检查:
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
是 ByteString 列表时,表达式 headers >>= BS.unpack
确实有意义并且等效于:
concat $ map BS.unpack headers
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 代码页(除了设置句柄编码,此处不适用)。
我知道如何通过解包将 ByteString 转换为 String,但我正在努力弄清楚如何将 IO ByteString(这是我从 HaskellNet 中的 fetchHeader 函数返回的)转换为 IO 字符串。我基本上是想做这样的事情
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 列表。
尝试使用 return $ BS.unpack headers
而不是 return (headers >>= BS.unpack)
。
或者尝试 return $ map BS.unpack headers
如果 headers 是一个 ByteString 列表。
除了它碰巧会进行类型检查(我假设 BS.unpack headers
有效)之外,还有一种思考方式:
headers
是纯值BS.unpack
是纯函数headers >>= ...
没有意义,因为>>=
的 LHS 需要是一元计算... >>= BS.unpack
没有意义,因为>>=
的 RHS 需要是一个产生单子计算的函数BS.unpack headers
是我们要的字符串return,但是是一个纯值- 因此我们使用
return
将纯值提升为一元计算
更新:
以下代码表明,如果 fetchHeader
的类型为 IO [BS.ByteString]
,那么您的代码将进行类型检查:
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
是 ByteString 列表时,表达式 headers >>= BS.unpack
确实有意义并且等效于:
concat $ map BS.unpack headers
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 代码页(除了设置句柄编码,此处不适用)。