Performance 为什么专门化具有标识的一元函数比手动编写效率低?
我需要两个高阶函数,一个取无副作用函数,另一个取一元函数作为参数:Performance 为什么专门化具有标识的一元函数比手动编写效率低?,performance,haskell,monads,higher-order-functions,Performance,Haskell,Monads,Higher Order Functions,我需要两个高阶函数,一个取无副作用函数,另一个取一元函数作为参数: frobM :: Monad m => (a -> m a) -> b -> m b frob :: (a -> a) -> b -> b 它们非常相似,第二个函数可以用第一个函数表示: frob f = runIdentity . frobM (return . f) 我希望这与“手工”编写frob一样高效,因为Identity是一种新类型,应该在编译时删除。然而,无论怎样,性能仍
frobM :: Monad m => (a -> m a) -> b -> m b
frob :: (a -> a) -> b -> b
它们非常相似,第二个函数可以用第一个函数表示:
frob f = runIdentity . frobM (return . f)
我希望这与“手工”编写frob
一样高效,因为Identity
是一种新类型,应该在编译时删除。然而,无论怎样,性能仍然受到影响,这一标准微观基准证明了这一点:
import Criterion.Main (bench, defaultMain, nf)
import Data.Functor.Identity (Identity (runIdentity))
main :: IO ()
main = defaultMain
[ bench "frob" $ nf (frob (+23)) 42
, bench "frob'" $ nf (frob' (+23)) 42
]
-- | Generalized function
frobM :: Monad m => (Int -> m Int) -> Int -> m Int
frobM f n = f $ 2^n `mod` 1024
-- | Specialized function based on the general function
frob' :: (Int -> Int) -> Int -> Int
frob' f = runIdentity . frobM (return . f)
-- | "Hand written" specialized function.
frob :: (Int -> Int) -> Int -> Int
frob f n = f $ 2^n `mod` 1024
输出:
benchmarking frob
time 676.1 ns (673.5 ns .. 678.9 ns)
1.000 R² (1.000 R² .. 1.000 R²)
mean 675.7 ns (673.3 ns .. 677.3 ns)
std dev 6.600 ns (5.984 ns .. 7.324 ns)
benchmarking frob'
time 706.2 ns (705.0 ns .. 707.9 ns)
1.000 R² (1.000 R² .. 1.000 R²)
mean 705.7 ns (704.5 ns .. 707.4 ns)
std dev 4.630 ns (3.729 ns .. 6.226 ns)
这是什么原因造成的?有没有办法使
frob'
和frob
一样高效?无法复制。使用ghc-7.10-O2
,我得到frob
和frob'
的时间为116纳秒;使用-O
时,每台为125纳秒。(您确实使用了优化标志,对吗?)只是为了确保:当您打开优化时,您还使用了-fforce recomp
?否则,除非文件本身已更改,否则GHC将不会执行任何操作。@leftaroundabout是这样做的!万分感谢!通常,这种情况在我身上发生过好几次。@leftaroundabout听起来像是一个答案:)无法复制。使用ghc-7.10-O2
,我得到frob
和frob'
的时间为116纳秒;使用-O
时,每台为125纳秒。(您确实使用了优化标志,对吗?)只是为了确保:当您打开优化时,您还使用了-fforce recomp
?否则,除非文件本身已更改,否则GHC将不会执行任何操作。@leftaroundabout是这样做的!万分感谢!“很普通,这在我身上发生过好几次。@leftaroundabout听起来像是一个答案:)