這是我的代碼的簡化:
import Database.PostgreSQL.Simple (Connection)
import qualified Streaming.Prelude as S
import Streaming.ByteString.Char8 as C
import Streaming.Zip (gunzip)
import Streaming
main :: IO ()
main = do
res <- runResourceT $ calculateA myLinesStream
return ()
type MyLinesStream m r = S.Stream (S.Of String) m r
connect :: IO Connection
connect = undefined
close :: Connection -> IO ()
close = undefined
calculateA :: MonadIO m => MyLinesStream m r -> m ()
calculateA stream = liftIO (bracket connect close (go stream))
where
go :: MonadIO m => MyLinesStream m r -> Connection -> m ()
go stream conn = stream & S.length_ >>= liftIO . print
myLinesStream :: (MonadIO m, MonadResource m) => MyLinesStream m ()
myLinesStream = do
S.each ["1.zip", "2.zip"]
& S.mapM (\fileName -> C.readFile fileName & gunzip)
& S.mconcat
& C.lines
& mapsM (S.toList . C.unpack)
& void
在以下行中存在型別錯誤go stream:
calculateA stream = liftIO (bracket connect close (go stream))
錯誤說:
Couldn't match type ‘m’ with ‘IO’
‘m’ is a rigid type variable bound by
the type signature for:
calculateA :: forall (m :: * -> *) r.
MonadIO m =>
MyLinesStream m r -> m ()
Expected type: Connection -> IO ()
Actual type: Connection -> m ()
問題
- 怎樣做才能使這個代碼型別檢查并且仍然保證在
calculateA函式中釋放資源是安全的? - 我正在使用讀取多個檔案
C.readFile,然后將其包裝在runResourceT. 這會正確釋放所有檔案句柄嗎? - 配樂好不好?(請注意,我需要與
calculateA分開的功能myLinesStream)
uj5u.com熱心網友回復:
問題是你試圖使用bracket一個過于籠統的單子。bracket有簽名:
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
它將IO動作作為引數。但是,go您傳遞給的函式bracket需要m在呼叫者選擇的通用基本 monad 中作業calculateA(您稍后將該 monad 設定為ResourceT IOin main)。
從基地和bracket不要很好地混合。相反,您需要從 resourcet 包中使用特殊函式,例如and ,并使用它們來定義一個幫助器,例如:ResourceTallocaterelease
bracketStream :: (Functor f, MonadResource m)
=> IO a
-> (a -> IO ())
-> (a -> Stream f m b)
-> Stream f m b
bracketStream alloc free inside = do
(key, seed) <- lift (allocate alloc free)
r <- inside seed
release key
pure r
它是如何作業的?如果您有一個Xs 流,它會在流的開頭添加一個分配操作(注冊在例外終止的情況下要呼叫的相應清理操作,例如例外),并且它還會在流已用盡:
(分配 注冊清理)XXX ... X(清理)
你寫了:
我正在使用 C.readFile 讀取多個檔案,然后將其包裝在 runResourceT 中。這會正確釋放所有檔案句柄嗎?
是的。With ResourceT,當執行顯式清理操作時,或者當我們“退出” ResourceTwith 時runResourceT(可能是例外的,有例外),資源被釋放。
因此,如果我們讀取一個 X 流,然后是一個 Y 流,我們將有:
(allocate register cleanup) X X X ... X (cleanup) (allocate register cleanup) Y Y Y ... Y (cleanup)
也就是說,產生 Xs 的資源將在分配產生 Ys 的資源之前被釋放。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/427266.html
上一篇:如何在haskell中過濾掉?
