【问题标题】:ByteString to lazy Text and vice versaByteString 到惰性文本,反之亦然
【发布时间】:2013-09-12 14:30:20
【问题描述】:

我在将 ByteString 转换为 Text 时遇到问题,反之亦然。代码如下:

{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Web.ClientSession

import Data.Text.Lazy (Text, toStrict, fromStrict)
import Data.Text.Lazy.Encoding (encodeUtf8, decodeUtf8)
import Data.ByteString (ByteString)

import Data.Monoid ((<>))

initCookies :: IO (Text -> ActionM ())
initCookies = do
  key <- getDefaultKey
  return $ setCookie key
  where
    setCookie k id = encryptIO k (encode id) 
      >>= (\x -> header "Set-Cookie" ("sid=" <> decode x <> ";"))

encode :: Text -> ByteString
encode = encodeUtf8 . toStrict

decode :: ByteString -> Text
decode = fromStrict . decodeUtf8

和错误信息:

foo.hs:16:35:
Couldn't match expected type `bytestring-0.10.0.2:Data.ByteString.Internal.ByteString'
with actual type `ByteString'
In the return type of a call of `encode'
In the second argument of `encryptIO', namely `(encode id)'
In the first argument of `(>>=)', namely `encryptIO k (encode id)'

foo.hs:17:18:
Couldn't match type `ActionM' with `IO'
Expected type: IO ()
Actual type: ActionM ()
In the return type of a call of `header'
In the expression: header "Set-Cookie" ("sid=" <> decode x <> ";")
In the second argument of `(>>=)', namely
`(\ x -> header "Set-Cookie" ("sid=" <> decode x <> ";"))'

foo.hs:17:56:
Couldn't match expected type `ByteString'
with actual type `bytestring-0.10.0.2:Data.ByteString.Internal.ByteString'
In the first argument of `decode', namely `x'
In the first argument of `(<>)', namely `decode x'
In the second argument of `(<>)', namely `decode x <> ";"'

所以,我猜这个错误与 ClientSession 实际使用的内容有关,在他们的源代码中,他们似乎使用了正常的字节串,这应该适用于我的实现。看这里:

[..]
import qualified Data.ByteString as S
[..]
encryptIO :: Key -> S.ByteString -> IO S.ByteString
[..]

那么为什么我会收到所有这些错误?谢谢。

【问题讨论】:

  • 你是否安装了多个版本的字节串?
  • 不,据我所知只有 bytestring-0.10.2.0。也许 Web.ClientSession 使用的是不同的?
  • ghc 错误信息包含带有包名的完全限定类型,如bytestring-0.10.0.2:Data.ByteString.Internal.ByteString,那么你的包间接依赖于两个不同版本的包有99%。 @bennofs 猜测很可能是正确的。 ghc-pkg list bytestring的帖子输出
  • 是的,这就是问题所在,谢谢!

标签: haskell text types bytestring


【解决方案1】:

你正在混合Data.ByteString.ByteStringData.ByteString.Lazy.ByteString。因为类型名称是相等的,所以 GHC 可以(并且确实)产生可怕的错误消息。我使用 ByteStringText 的显式导入对其进行了重新设计,希望现在更加明显:

{-# LANGUAGE OverloadedStrings #-}

import Web.Scotty
import Web.ClientSession

import Control.Monad.Trans (liftIO)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TL
import qualified Data.ByteString as B
import qualified Data.ByteString as BL

import Data.Monoid ((<>))

initCookies :: IO (TL.Text -> ActionM ())
initCookies = do
  key <- getDefaultKey
  return $ setCookie key
  where
    setCookie k id = liftIO (encryptIO k (encode id))
      >>= (\x -> header "Set-Cookie" ("sid=" <> decode x <> ";"))

encode :: TL.Text -> B.ByteString
encode = T.encodeUtf8 . TL.toStrict

decode :: B.ByteString -> TL.Text
decode = TL.fromStrict . T.decodeUtf8

【讨论】:

  • sn-p 只导入Data.ByteString。并且错误抱怨ByteStringbytestring-0.10.0.2:Data.ByteString.Internal.ByteString,两者都是严格的字节字符串。懒惰的在Data.ByteString.Lazy.Internal.ByteString 中声明。我错过了什么?
  • @Yuras:Data.Text.Lazy.Encoding 模块处理 Data.ByteString.Lazy.ByteStrings 不是严格的,但错误消息具有误导性。
  • 您指的是encodedecode 中的类型错误。但是作者在initCookies (foo.hs:16:35) 中有错误,这绝对是关于不同的bytestring 版本。当他解决该问题时,他也会收到您所指的错误。我不是说你错了,但最初的问题是关于依赖地狱。
  • @Yuras 看来你是对的,但无论如何它都不会编译 :^)
【解决方案2】:

Data.String.Conversions 包使用单个 cs 转换函数抽象化该知识,调用哪个版本取决于调用的上下文(即输入和预期类型)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2012-02-16
    • 2013-08-16
    • 2012-06-27
    • 2017-02-05
    • 2012-12-01
    相关资源
    最近更新 更多