GHC 是否为 `mapM_` 生成优化代码?
Does GHC generate optimized code for `mapM_`?
这段代码是我写的,
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
这是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 #-}
表达式 mapM_ ((appendFile fpAcc =<<) . readFile)
是否对磁盘产生了 3 次写入操作,或者由于某种 GHC 优化,只有一次?
如果编译器可以生成使用中间存储器保存附加数据然后只写入一次的代码,那就太好了。但是,由于 mapM_
将结构的每个元素映射到一个单子操作,因此可能每个步骤执行一个写操作。
不,这没有优化。您编写的代码将打开 fpAcc
,写入一些字节,并为路径中的每个元素关闭一次 fpAcc
。事实上,编译器优化这个是不正确的:打开和关闭文件是从程序外部观察到的,所以只打开文件一次的优化将是行为改变,而不仅仅是速度改变。
这段代码是我写的,
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
这是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 #-}
表达式 mapM_ ((appendFile fpAcc =<<) . readFile)
是否对磁盘产生了 3 次写入操作,或者由于某种 GHC 优化,只有一次?
如果编译器可以生成使用中间存储器保存附加数据然后只写入一次的代码,那就太好了。但是,由于 mapM_
将结构的每个元素映射到一个单子操作,因此可能每个步骤执行一个写操作。
不,这没有优化。您编写的代码将打开 fpAcc
,写入一些字节,并为路径中的每个元素关闭一次 fpAcc
。事实上,编译器优化这个是不正确的:打开和关闭文件是从程序外部观察到的,所以只打开文件一次的优化将是行为改变,而不仅仅是速度改变。