2016-07-12 39 views
1

作为学习Haskell,Conduit和Monads的一个练习,我想创建一个输入值并将其传递的管道。在Haskell中使用Writer monad和Conduit

代码非常简单,但我发现了仍在神秘的对我来说编译错误:

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 } 
+0

这种类型的检查我http://lpaste.net/169714这可能是一些关于进口? – Michael

+0

说明,你可能打算为'log'管继续它击中的第一个项目后的方式。因为只有一件物品可以通过。所以,你应该循环递归,或者使用'awaitForever'等。 – Michael

回答

3

这里对我来说是什么在起作用:

{-# 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() 
+0

谢谢@ErikR你的答案钉它。 我会很感激,如果你能解释如何推断出错误消息的类型签名。 –

+0

答复已更新。 – ErikR