Home > Software engineering >  Does GHC generate optimized code for `mapM_`?
Does GHC generate optimized code for `mapM_`?

Time:04-12

I wrote this code,

import System.FilePath ((</>))

fp = "/Users/USER/Documents/Test/"

fpAcc = fp </> "acc.txt"

paths = map (fp </>) ["A.txt", "B.txt", "C.txt"]

main :: IO ()
main =
    writeFile fpAcc ""
        >> return paths
        >>= mapM_ ((appendFile fpAcc =<<) . readFile)
        >> readFile fpAcc >>= putStrLn

and this is the definition of mapM_:

mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
mapM_ f = foldr c (return ())
-- See Note [List fusion and continuations in 'c']
where c x k = f x >> k
    {-# INLINE c #-}

Is the expression mapM_ ((appendFile fpAcc =<<) . readFile) producing 3 write operations to the disk, or due to some kind of GHC optimization, only one?

Would be great if the compiler could generate code that uses an intermediate memory to hold the appended data and then write only once. But, since mapM_ maps each element of the structure to a monadic action, perhaps each step performs one write operation.

CodePudding user response:

No, this is not optimized. The code you wrote will open fpAcc, write some bytes, and close fpAcc once for each element in paths. Indeed, it would be incorrect for the compiler to optimize this: opening and closing a file is observable from outside the program, so an optimization that opened the file just once would be a behavioral change, not just a speed change.

  • Related