2017-01-16 6 views
0

Ich habe eine Typklasse, die einige IO ausführt. Ich habe es verallgemeinert ein wenig mit MonadIO:Testen einer Typklasse mit MonadIO: "Keine Instanz oder Standardmethode" Fehler

class MonadIO m => MonadDB m where 
    getSomething :: String -> m Something 
    getSomething s = -- do some IO stuff with liftIO 

In einem Test möchte ich die Implementierung ersetzen, damit ich eine Funktion testen, die getSomething verwendet, so dass ich dies tun:

newtype WorkingDBM a = WorkingDBM (Identity a) 
    deriving (Functor, Applicative, Monad) 

instance MonadDB WorkingDBM where 
    getSomething s = return $ Something "blah" 

Ohne ein Beispiel Erklärung warnt der Code:

• No explicit implementation for ‘liftIO’ 
• In the instance declaration for ‘MonadIO WorkingDBM’ 

So füge ich:

instance MonadIO WorkingDBM 

was natürlich kompiliert.

die Tests in HSPEC Lauf Ursachen dieser Laufzeitfehler:

uncaught exception: NoMethodError (test/BlahSpec.hs:45:10-33: No instance nor default method for class operation liftIO 

ich versucht habe, mit liftIO von Control.Monad.IO.Class:

-- C is the qualified import for Control.Monad.IO.Class 
liftIO = C.liftIO 

aber dies führt zu einer NonTermination Laufzeitausnahme:

uncaught exception: NonTermination (<<loop>>) 

Irgendwelche Ideen, wie ich t auflösen kann sein bitte?

+0

Tun Sie in Ihrem Test nicht 'IO' oder unterstützen Sie' IO' in 'WorkingDBM'. –

+0

Es stellte sich heraus, dass es in der Funktion, die ich getestet habe, "liftIO" war, also kann ich das IO nicht tun. Was meinst du Unterstützung real? Ich dachte, 'MonadIO' würde dafür ausreichen. –

+1

Ich habe eine Antwort geschrieben mit einigen weiteren Details, was ich meine. Aber ich stelle Ihre Behauptung in Frage, dass Sie in Ihrem Test "IO" innerhalb der "MonadDB" -Instanz ausführen müssen. –

Antwort

1

Eine Lösung ist die Unterstützung von IO in WorkingDBM. Zum Beispiel:

newtype WorkingDBM a = WorkingDBM (IO a) -- N.B. IO not Identity 
    deriving (Functor, Applicative, Monad) 

instance MonadIO WorkingDBM where 
    liftIO = WorkingDBM 

Die abgeleitete Instanz für MonadIO auch gut funktioniert; aber die leere Instanz wird nicht, wie es entspricht

ist
instance MonadIO WorkingDBM where 
    liftIO = undefined 

, die offensichtlich das erste Mal sprengen werden Sie tatsächlich versuchen, zu IO tun.

+0

Danke. Wie würde ich die Verwendung von 'WorkingDBM' erzwingen? Ich verwende derzeit 'unWorkingDBM (WorkingDBM (Identity x)) = x' in meinem Test, was den Compiler offensichtlich dazu bringt, meine "Teste-Instanz" von 'MonadDB' zu verwenden. Wird kein Äquivalent verwendet, wenn 'IO a' verwendet wird (weil kein Datenkonstruktor für' IO' steht, kann ich den Compiler nicht zur Verwendung der Testinstanz drücken (abgeleitet oder anders ...) –

+0

@atc Sie können immer noch 'schreiben runWorkingDBM (WorkingDBM x) = x', du musst es nur geben 'runWorkingDBM :: WorkingDBM a -> IO a' statt' runWorkingDBM :: WorkingDBM a -> a' –

+0

Danke für deine Hilfe, die es löst ! :) –

Verwandte Themen