Отсутствует тип результата?По длине функции :: Monad m => ByteString mr -> m (Of Int r) - PullRequest
2 голосов
/ 14 мая 2019

У меня есть простая функция, которая читает двоичный файл по одному байту за раз. Это получает ошибку времени компиляции, ниже. Кажется, проблема в том, что bs2, результирующая строка байтов BSSC.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)

Ответы [ 2 ]

1 голос
/ 14 мая 2019

Тип ByteString из streaming-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).Он потребляет поток значений, полученный в качестве аргумента, и возвращает действие в базовой монаде.ByteString больше не существует.bs2, который вы передаете splitAt, это не ByteString, а конечное значение исходного ByteString, имеющего тип r.И это вызывает ошибку типа.

0 голосов
/ 14 мая 2019

Можно исправить несоответствие типов, используя 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

У меня нет компилятора, поэтому, возможно, в моих фрагментах есть проблемы компиляции.

...