Zuerst, eine vereinfachte Version der Aufgabe, die ich erreichen möchte: Ich habe mehrere große Dateien (in Höhe von 30 GB), die ich für doppelte Einträge löschen möchte. Zu diesem Zweck errichte ich eine Datenbank mit Hashes der Daten und öffne die Dateien einzeln, hashe jedes Element und zeichne es in der Datenbank und der Ausgabedatei auf, wenn sein Hash nicht bereits in der Datenbank vorhanden ist.Verwendung von persistent aus einem Conduit
Ich weiß, wie dies mit iterates, Enumeratoren zu tun, und ich wollte Conduits versuchen. Ich weiß auch, wie man es mit Conduits macht, aber jetzt möchte ich Conduits & persistent verwenden. Ich habe Probleme mit den Typen und möglicherweise mit dem gesamten Konzept von ResourceT
.
Hier einig Pseudo-Code, um das Problem zu veranschaulichen:
withSqlConn "foo.db" $ runSqlConn $ runResourceT $
sourceFile "in" $= parseBytes $= dbAction $= serialize $$ sinkFile "out"
Das Problem liegt in der dbAction
Funktion. Ich möchte natürlich hier auf die Datenbank zugreifen. Da die Maßnahmen, die sie im Grunde tut, ist nur ein Filter, dachte ich zuerst, dass es so schreiben:
dbAction = CL.mapMaybeM p
where p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) => DataType -> m (Maybe DataType)
p = lift $ putStrLn "foo" -- fine
insert $ undefined -- type error!
return undefined
Der spezifische Fehler ich erhalte, ist:
Could not deduce (m ~ b0 m0)
from the context (MonadIO m, MonadBaseControl IO (SqlPersist m))
bound by the type signature for
p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) =>
DataType -> m (Maybe DataType)
at tools/clean-wac.hs:(33,1)-(34,34)
`m' is a rigid type variable bound by
the type signature for
p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) =>
DataType -> m (Maybe (DataType))
at tools/clean-wac.hs:33:1
Expected type: m (Key b0 val0)
Actual type: b0 m0 (Key b0 val0)
Beachten Sie, dass dies zu falschen Annahmen zurückzuführen sein könnte Ich habe die Typensignatur entworfen. Wenn ich die Art Unterschrift kommentieren und auch die lift
Anweisung entfernen, wird die Fehlermeldung in:
No instance for (PersistStore ResourceT (SqlPersist IO))
arising from a use of `p'
Possible fix:
add an instance declaration for
(PersistStore ResourceT (SqlPersist IO))
In the first argument of `CL.mapMaybeM', namely `p'
So bedeutet dies, dass wir nicht die PersistStore
überhaupt über ResourceT
zugreifen können?
Ich kann meine eigene Conduit entweder nicht schreiben, ohne CL.mapMaybeM
mit:
dbAction = filterP
filterP :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) => Conduit DataType m DataType
filterP = loop
where loop = awaitE >>= either return go
go s = do lift $ insert $ undefined -- again, type error
loop
Diese noch in einer anderen Art Fehler geführt Ich verstehe nicht ganz.
Also, meine Frage ist: ist es möglich zu verwenden hartnäckig wie ich in einem Conduit überhaupt wollte? Und wenn, wie? Ich bin mir bewusst, dass, da ich liftIO
innerhalb des Conduit verwenden kann, ich einfach gehen und sagen könnte HDBC
, aber ich wollte hartnäckig explizit verwenden, um zu verstehen, wie es funktioniert, und weil ich seine db-Backend-Agnostizismus mag.
Haben Sie versucht, statt 'liftIO' mit' lift'? –
Ah, ja, sicher "LiftIO" auferlegt dem gesamten Do-Block eine Einschränkung. Aber das erklärt nur, warum die erste Fehlermeldung von der zweiten abweicht. Ich werde den Beitrag in einer Sekunde aktualisieren, um zu reflektieren, was passiert, wenn Sie die Anweisung von LiftIO entfernen. –
BTW, sogar "Lift" auferlegt dem Monad-Typ bereits "IO" -Einschränkungen. Ich habe bemerkt, dass du die Anweisung 'lift' * entfernen musst, um diese Fehlermeldung zu erhalten. Wenn Sie dies nicht tun (aber 'lift $ print" "' in) beibehalten, erhalten Sie stattdessen 'Konnte nicht mit dem erwarteten Typ 'SqlPersist m0 a0' mit dem tatsächlichen Typ 'IO()' übereinstimmen. –