首先,我想要完成的任務的簡化版本:我有幾個大文件(總計30GB),我希望修剪重複條目。爲此,我建立了一個數據散列數據庫,並逐個打開這些文件,散列每個項目,並將其記錄在數據庫和輸出文件中(如果散列不在數據庫中)。從Conduit中使用持久性
我知道如何用iteratees和枚舉器來做到這一點,我想試試管道。我也知道如何用管道做到這一點,但現在我想用管道&執行。我遇到了各種類型的問題,可能還有ResourceT
的整個概念。
下面是一些僞代碼來說明這個問題:
withSqlConn "foo.db" $ runSqlConn $ runResourceT $
sourceFile "in" $= parseBytes $= dbAction $= serialize $$ sinkFile "out"
問題在於dbAction
功能。自然,我想在這裏訪問數據庫。由於它的作用基本上是一個過濾器,我首先想到把它寫這樣的:
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
特定的錯誤我得到的是:
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)
注意,這可能是由於錯誤的假設我在設計類型簽名。如果我註釋掉類型簽名,也拆除lift
說法,錯誤消息變成:
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'
因此,這意味着我們無法通過ResourceT
訪問PersistStore
呢?
我不能寫我自己的管道要麼不使用CL.mapMaybeM
:
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
這導致了另一種類型的錯誤,我不完全理解。
Could not deduce (m ~ b0 m0)
from the context (MonadIO m, MonadBaseControl IO (SqlPersist m))
bound by the type signature for
filterP :: (MonadIO m,
MonadBaseControl IO (SqlPersist m)) =>
Conduit DataType m DataType
`m' is a rigid type variable bound by
the type signature for
filterP :: (MonadIO m,
MonadBaseControl IO (SqlPersist m)) =>
Conduit DataType m DataType
Expected type: Conduit DataType m DataType
Actual type: Pipe
DataType DataType DataType() (b0 m0)()
In the expression: loop
In an equation for `filterP'
所以,我的問題是:是否有可能使用持久性,就像我打算在導管裏一樣?如果,如何?我知道,因爲我可以在管道內使用liftIO
,所以我可以去使用,但我想明確地使用persistent,以瞭解它是如何工作的,並且因爲我喜歡它的db-backend不可知論。
您是否嘗試過使用'lift',而不是'liftIO'? –
啊,是的,當然'liftIO'對整個'do'塊施加一個約束。但這隻能解釋爲什麼第一個錯誤信息與第二個錯誤信息不同。我會在一秒內更新這篇文章,以反映如果您刪除liftIO聲明會發生什麼情況。 –
順便說一句,即使'lift'已經對monad類型施加了'IO'限制。我注意到你必須*刪除* lift'語句以達到該錯誤信息。如果你不這樣做(但是保留'lift $ print「」'in),你會得到'不能與實際類型'IO()'匹配的預期類型'SqlPersist m0 a0'。 –