2016-07-12 32 views
1

Als eine Übung zum Lernen Haskell, Conduit und Monaden, möchte ich eine Leitung erstellen, teilt den Eingangswert und übergibt es.Verwenden der Writer-Monade mit Conduit in Haskell

-Code ist ziemlich einfach, aber ich bin immer Kompilierungsfehler, die für mich nach wie vor rätselhaft ist:

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

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

Und der Fehler:

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

Diese Kontrollen für mich http://lpaste.net/169714 Könnte es etwas über die Importe sein? – Michael

+0

Beachten Sie übrigens, dass Sie wahrscheinlich beabsichtigen, dass die 'log'-Pipe nach dem ersten Treffer weiterläuft. Da kann nur ein Gegenstand passieren. Sie sollten also rekursiv loopen oder 'awaistForever' oder ähnliches verwenden. – Michael

Antwort

3

Hier ist, was für mich funktioniert:

{-# 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 

Hinweis Ich habe den Namen von log in doit geändert, um den Namenskonflikt zu vermeiden mit Prelude.log.

aktualisieren

Wenn Sie beginnen mit:

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 

werden Sie zwei Fehlermeldungen erhalten:

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

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

Seit doit ist ein Top-Level-Funktion, Erfahrung wird Ihnen sagen, dass vielleicht die Monomorphie-Einschränkung hier funktioniert. der Tat, nach Zugabe:

{-# LANGUAGE NoMonomorphismRestriction #-} 

Sie erhalten nur einen Fehler:

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

Und nach FlexibleContexts Zugabe kompiliert der Code.

Jetzt können Sie die Art der doit verhören:

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

Danke @ErikR deine Antwort hat es genagelt. Ich würde mich freuen, wenn Sie erklären könnten, wie Sie die Typ-Signatur aus der Fehlermeldung ableiten können. –

+0

Antwort aktualisiert. – ErikR