Выражение чтения простого файла Conduit без проверки типов

Я пытаюсь получить пример простого канала, но у меня не получается этап проверки типа. В этом примере я видя, как ResourceT используется в качестве "исполнителя" канала, если это имеет смысл. Я также знаю, что в течение некоторого времени ResourceT был выделен в отдельный пакет. Тем не менее, я все еще не могу заставить работать простой пример. Вот мой код, вдохновленный этой статьей. :

import qualified Data.Conduit as C
import qualified Data.Conduit.Binary as CB
import qualified Data.Conduit.List as CL
import Control.Monad.Trans.Resource (runResourceT)
import Data.ByteString.Char8 (unpack)
import Data.ByteString (ByteString (..))
import System.IO

printFile file = runResourceT $ CB.sourceFile file C.$$ print'
  where
    print' :: C.Sink ByteString IO ()
    print' = CL.mapM_ $ putStrLn · unpack

И вот ошибка, которую я получаю (мой пакет называется "conduit-playground":

Preprocessing library conduit-playground-0.0.0...
[2 of 2] Compiling Playground       ( src/Playground.hs, dist/dist-sandbox-13da96d6/build/Playground.o )

src/Playground.hs:12:57:
    Couldn't match type ‘IO’
                  with ‘Control.Monad.Trans.Resource.Internal.ResourceT m’
    Expected type: C.Sink
                     ByteString (Control.Monad.Trans.Resource.Internal.ResourceT m) ()
      Actual type: C.Sink ByteString IO ()
    Relevant bindings include
      printFile :: FilePath -> m () (bound at src/Playground.hs:12:1)
    In the second argument of ‘(C.$$)’, namely ‘print'’
    In the second argument of ‘($)’, namely
      ‘CB.sourceFile file C.$$ print'’
cabal: Error: some packages failed to install:
conduit-playground-0.0.0 failed during the building phase. The exception was:
ExitFailure 1

Если я пропущу runResourceT, я все равно получу ошибку класса типов из-за отсутствия экземпляра MonadResource для IO. Как мне решить эту проблему?


person Athan Clark    schedule 10.09.2014    source источник
comment
Я не знаком с ResourceT, но, похоже, вы пытаетесь форсировать тип печати, который не соответствует стеку трансформатора. Что произойдет, если вы удалите явную подпись?   -  person Sarah    schedule 11.09.2014
comment
Предполагается, что print' является Conduit вместо Sink, что приводит к еще большему количеству ошибок типа:/   -  person Athan Clark    schedule 11.09.2014
comment
Я думаю, что на самом деле это сводится к тому, что экземпляр MonadResource не используется для IO. Например, CL.mapM_ putStrLn :: MonadResource m => Sink String m () не работает; экземпляра нет (вероятно, по уважительной причине).   -  person Athan Clark    schedule 11.09.2014


Ответы (1)


Проблема в том, что ваш print' имеет несовместимый тип

print' :: C.Sink ByteString IO ()

Вы не можете иметь IO в качестве базовой монады канала, если вы используете ResourceT (который вам нужен в этом случае для чтения файла). Самая простая монада, которая позволяет вам как печатать, так и обрабатывать файловые ресурсы, — это ResourceT IO, т. е. монада IO, преобразованная преобразователем ResourceT.

print' :: C.Sink ByteString (ResourceT IO) ()
print' = CL.mapM_ $ liftIO . putStrLn · unpack

liftIO нужен, чтобы "поднять" выражение типа IO () в ResourceT IO (). Вы также можете использовать более общую подпись

print' :: MonadIO m => C.Sink ByteString m ()

сделать служебную функцию, которая работает с любым каналом, способным выполнять ввод-вывод.

MonadIO и liftIO можно импортировать из модуля Control.Monad.IO.Class.

person shang    schedule 11.09.2014