External Publication
Visit Post

Conduit to yield first lines from file without leaking space or file handles?

Haskell Community [Unofficial] May 2, 2026
Source

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

Loading comments...