Conduit to yield first lines from file without leaking space or file handles?
Haskell Community [Unofficial]
May 2, 2026
Thanks for looking into it! Unfortunately I don’t think the problem can be solved by making takeRes ResourceT-aware. After all, there may be no resource at all, and even if there is, it doesn’t know which one to free. For example, some other resource can be released too soon:
{- cabal:
build-depends: base, text, directory, conduit, resourcet
-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE LambdaCase #-}
import Conduit
import Control.Monad.Trans.Resource
import Control.Monad.Trans.Resource.Internal
import Data.Conduit.Combinators qualified as CC
import Data.IORef
main :: IO ()
main =
runConduitRes $
bracketP
(pure ())
(\() -> putStrLn "should close at end")
( \() ->
CC.enumFromTo (1 :: Int) 4
.| awaitForever
( \x ->
bracketP
(pure ())
(\_ -> putStrLn "close")
(\_ -> CC.enumFromTo (1 :: Int) x)
.| takeRes 3
)
.| CC.mapM_ (liftIO . print)
.| sinkNull
)
takeRes :: (MonadResource m) => Int -> ConduitT a a m ()
takeRes 0 = liftResourceT $ do
is <- getInternalState
closeInternalState is
liftIO $ writeIORef is $ ReleaseMap maxBound (minBound + 1) mempty
takeRes n =
await >>= \case
Nothing -> mempty
Just x -> yield x *> takeRes (n - 1)
ghci> main
1
close
1
2
close
1
2
3
close
should close at end
1
2
3
close
Discussion in the ATmosphere