2

我有一个简单的函数,一次读取一个字节的二进制文件。它得到一个编译时错误,如下所示。问题似乎是bs2,得到的 ByteStringBSSC.length具有未知类型。我错过了类型约束r吗?

import qualified Data.ByteString.Streaming.Char8 as BSSC

main :: IO ()
main = runResourceT $ dump $ BSSC.readFile "filename"

dump :: (MonadIO m) => BSSC.ByteString m r -> m ()                                                                                                                                                
dump bs = do
    len :> bs2 <- BSSC.length bs          -- Data.Functor.Of (:>)
    if len <= 1 then return ()
    else dump $ BSSC.putStr $ BSSC.splitAt 1 bs2

编译时错误:

Main.hs:166:46: error:
  • Couldn't match expected type ‘BSSC.ByteString
                                    (BSSC.ByteString m) r0’
                with actual type ‘r’
    ‘r’ is a rigid type variable bound by
      the type signature for:
        dump :: forall (m :: * -> *) r.
                MonadIO m =>
                BSSC.ByteString m r -> m ()
      at Main.hs:162:9
  • In the second argument of ‘BSSC.splitAt’, namely ‘bs2’
    In the second argument of ‘($)’, namely ‘BSSC.splitAt 1 bs2’
    In the second argument of ‘($)’, namely
      ‘BSSC.putStr $ BSSC.splitAt 1 bs2’
  • Relevant bindings include
      bs2 :: r (bound at Main.hs:164:12)
      bs :: BSSC.ByteString m r (bound at Main.hs:163:6)
      dump :: BSSC.ByteString m r -> m () (bound at Main.hs:163:1)
4

2 回答 2

1

streaming-bytestring 中的ByteString类型有两个类型参数。第一个是m产生值的基本单子(通常是IO)。

第二个是一个特殊的结束值r,一旦ByteString用完就会返回。通常它将是无信息的()。但是,它对于定义诸如splitAt :: Monad m => Int64 -> ByteString m r -> ByteString m (ByteString m r). 类型的意思是:“给我一个限制位置和一个返回的有效字节流r,我会给你另一个不超过限制的流,并返回一个有效的字节流,返回一个r。” 嵌套在外部流中的这个结束流只有在外部流耗尽后才能到达。

length有类型Monad m => ByteString m r -> m (Of Int r)。它使用作为参数接收的值流,并在基本 monad 中返回一个动作。ByteString不再存在。bs2您传递给的splitAt不是 aByteString而是原始的结束值ByteString,它具有 type r。这会导致类型错误。

于 2019-05-14T18:09:41.793 回答
0

您可以使用bs作为第二个参数来修复类型不匹配splitAt

import qualified Data.ByteString.Streaming.Char8 as BSSC

main :: IO ()
main = runResourceT $ dump $ BSSC.readFile "filename"

dump :: (MonadIO m) => BSSC.ByteString m r -> m ()                                                                                                                                                
dump bs = do
    len :> bs2 <- BSSC.length bs
    if len <= 1 then return ()
    else dump $ BSSC.putStr $ BSSC.splitAt 1 bs

但它不会像你期望的那样工作。我猜它会读取文件中的字母数倍。

如果你想要递归,你应该去

import qualified Data.ByteString.Streaming.Char8 as BSSC

main :: IO ()
main = runResourceT $ dump $ BSSC.readFile "filename"

dump :: (MonadIO m) => BSSC.ByteString m r -> m ()                                                                                                                                                
dump bs = do
    split <- BSSC.uncons bs
    case split of
       Left _        -> return ()
       Right (x, xs) -> putStr (show x) >> dump xs

我没有编译器,所以我的代码片段中可能存在编译问题。

于 2019-05-14T10:40:29.887 回答