【问题标题】:Using the Writer monad with Conduit in Haskell在 Haskell 中将 Writer monad 与 Conduit 一起使用
【发布时间】:2016-07-12 23:57:01
【问题描述】:

作为学习 Haskell、Conduit 和 Monads 的练习,我想创建一个 告诉输入值并传递它的管道。

代码非常简单,但我遇到的编译错误对我来说仍然很神秘:

 log =
    await >>= \case
      Nothing -> return ()
      Just value -> do
        tell [value]
        yield value

 runWriter $ CL.sourceList ["a", "b"] $= log $$ CL.consume

还有错误:

 No instance for (MonadWriter [o0] m0) arising from a use of ‘tell’
 The type variables ‘m0’, ‘o0’ are ambiguous
 Relevant bindings include
   value :: o0
     (bound at /home/vagrant/workspace/dup/app/Main.hs:241:10)
   logg :: ConduitM o0 o0 m0 ()
     (bound at /home/vagrant/workspace/dup/app/Main.hs:238:1)
 Note: there are several potential instances:
   instance MonadWriter w m => MonadWriter w (ConduitM i o m)
     -- Defined in ‘conduit-1.2.6.4:Data.Conduit.Internal.Conduit’
   instance MonadWriter w m =>
            MonadWriter
              w (conduit-1.2.6.4:Data.Conduit.Internal.Pipe.Pipe l i o u m)
     -- Defined in ‘conduit-1.2.6.4:Data.Conduit.Internal.Pipe’
   instance [safe] MonadWriter w m =>
                   MonadWriter w  (Control.Monad.Trans.Resource.Internal.ResourceT m)
     -- Defined in ‘Control.Monad.Trans.Resource.Internal’
   ...plus 11 others
 In a stmt of a 'do' block: tell [value]
 In the expression:
  do { tell [value];
       yield value }
 In a case alternative:
    Just value
      -> do { tell [value];
              yield value }

【问题讨论】:

  • 这种类型会帮我检查lpaste.net/169714 会不会是进口的问题?
  • 请注意,您可能打算让log 管道在它命中的第一个项目之后继续。因为它只有一项可以通过。所以你应该递归循环,或者使用awaitForever之类的。

标签: haskell monads conduit


【解决方案1】:

这对我有用:

{-# LANGUAGE FlexibleContexts #-}

import Data.Conduit
import Control.Monad.Writer
import qualified Data.Conduit.List as CL

doit :: MonadWriter [i] m => Conduit i m i
doit = do
  x <- await
  case x of
    Nothing -> return ()
    Just v  -> do tell [v]; yield v; doit

foo = runWriter $ CL.sourceList ["a", "b", "c"] =$= doit $$ CL.consume

请注意,我将名称从 log 更改为 doit 以避免名称与 Prelude.log 冲突。

更新

如果你开始:

import Data.Conduit
import Control.Monad.Writer
import qualified Data.Conduit.List as CL

doit = do
  x <- await
  case x of
    Nothing -> return ()
    Just v -> do tell [v]; yield v; doit

你会得到两个错误:

No instance for (Monad m0) arising from a use of ‘await’
...

No instance for (MonadWriter [o0] m0) arising from a use of ‘tell’
...

既然doit是顶级函数,经验会告诉你 也许单态性限制在这里起作用。 确实,添加后:

{-# LANGUAGE NoMonomorphismRestriction #-}

你只会得到一个错误:

Non type-variable argument in the constraint: MonadWriter [o] m
(Use FlexibleContexts to permit this)
...

添加FlexibleContexts后,代码编译。

现在可以查询doit的类型了:

ghci> :t doit
doit :: MonadWriter [o] m => ConduitM o o m ()

【讨论】:

  • 感谢@ErikR,您的回答成功了。如果您能解释如何从错误消息中推断出类型签名,我将不胜感激。
猜你喜欢
  • 2012-06-30
  • 1970-01-01
  • 2018-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-26
相关资源
最近更新 更多