解决 "No instance for ..." 与导管的单遍历

Resolving "No instance for ..." with conduit's mono-traversable

给定以下代码:

import           Data.Attoparsec.Text
import qualified Conduit as C
import qualified Data.Conduit.Combinators as CC

f :: FilePath -> FilePath -> IO ()
f infile outfile =
  runResourceT $
    CC.sourceFile infile $$ C.encodeUtf8C =$= x

其中 x 的类型是 ConduitM Text Void (ResourceT IO) ()

我的私有 github 存储库中出现以下编译时错误:

• No instance for (mono-traversable-1.0.2:Data.Sequences.Utf8
                     ByteString Text)
    arising from a use of ‘C.encodeUtf8C’
• In the first argument of ‘(=$=)’, namely ‘C.encodeUtf8C’
  In the second argument of ‘($$)’, namely ‘C.encodeUtf8C =$= x’
  In the second argument of ‘($)’, namely
    ‘CC.sourceFile infile $$ C.encodeUtf8C =$= x’

如何解决这个编译时错误?

编辑

我对类型的理解:

> :t sourceFile
sourceFile
  :: MonadResource m =>
     FilePath
     -> ConduitM
          i bytestring-0.10.8.1:Data.ByteString.Internal.ByteString m ()

> :t ($$)
($$) :: Monad m => Source m a -> Sink a m b -> m b

> :t Conduit
type Conduit i (m :: * -> *) o = ConduitM i o m ()

> :i Source
type Source (m :: * -> *) o = ConduitM () o m ()

> :i Sink
type Sink i = ConduitM i Data.Void.Void :: (* -> *) -> * -> *

> :t (=$=)
(=$=)
  :: Monad m => Conduit a m b -> ConduitM b c m r -> ConduitM a c m r

C.encodeUtf8C =$= x归结为,我认为:

(mono-traversable-1.0.2:Data.Sequences.Utf8 text binary,
      Monad m) =>
     Conduit text m binary () 

=$= 

ConduitM Text Void binary () 

产生return类型的

ConduitM text Void (ResourceT IO) ()

而且我假设这种类型,即 C.encodeUtf8C =$= x,不统一到 CC.sourceFile 的预期第二个参数?

sourceFile 管道产生一个 ByteString,你需要 解码 Textx 使用. 编码指的是你序列化TextByteString写入文件的反方向

使用decodeUtf8.


为什么类型不匹配

-- Ignoring the `Monad` constraint.

(=$=)      :: Conduit a m b -> ConduitM b c m r -> ConduitM a c m r

encodeUtf8 :: Utf8 text binary
           => Conduit text m binary

x          :: ConduitM Text Void m ()

要将 (=$=) 应用到 encodeUtf8,您必须统一 Conduit a m bConduit text m binary,因此我们得到以下类型等式:

a ~ text
b ~ binary

然后我们将结果应用到x,统一ConduitM b c m rConduitM Text Void m ()

b ~ Text
c ~ Void

到这里编译器没有报错,但我们已经可以看到不匹配,因为涉及 b:

的两个等式
b ~ binary
b ~ Text

conduit-combinators 库中,类型变量 binary 用于引用表示原始二进制数据的类型,通常是 ByteString,而不是像 Text.

如果我们继续,结果的类型为 ConduitM a c m r,并将作为 ($$) 的第二个参数传递。

-- Expanding Source and Sink definitions, renaming type variables.

($$) :: Monad m => ConduitM () d m () -> ConduitM d Void m e -> m e

sourceFile infile
     :: _ => ConduitM i ByteString m ()

使用source infile作为第一个参数,我们统一ConduitM () d m ()ConduitM i ByteString m ()

i ~ ()
d ~ ByteString

并且将我们之前的encodeUtf8C =$= x作为($$)的第二个参数,我们统一了ConduitM d Void m eConduitM a c m r

a ~ d
c ~ Void
r ~ e

关注ad,我们有:

a ~ text
a ~ d
d ~ ByteString

因此text ~ ByteStringbinary ~ Text。现在请记住,要使用 encodeUtf8,我们需要一个 Utf8 text binary 约束,即 Utf8 ByteString Text,这是错误的方法。