我做了一些:
main = print $ head . drop (2^30) $ [1..]
-同时使用Prelude.drop
和琐碎的drop
。 Prelude变体的速度始终快约45%,我不知道为什么。我什至从GHC.List.drop
中提取了base-4.11.1.0
的定义,但它的表现比我的琐碎代码还差!发生了什么事?
这就是我在做什么:
% stack ghc -- --version
The Glorious Glasgow Haskell Compilation System, version 8.2.2
Prelude.drop
:
% git checkout drop-prelude
% git clean --force
% cat ListTest.hs
module Main where
main = print $ head . drop (2^30) $ [1..]
% stack ghc -- ListTest.hs
[1 of 1] Compiling Main ( ListTest.hs, ListTest.o )
Linking ListTest ...
% time ./ListTest
1073741825
./ListTest 18.76s user 0.09s system 99% cpu 18.906 total
琐碎的drop
:
% git checkout drop-naive
% git clean --force
% cat ListTest.hs
module Main where
dropNaive :: Int -> [a] -> [a]
dropNaive 0 xs = xs
dropNaive n [ ] = [ ]
dropNaive n (x: xs) = dropNaive (pred n) xs
main = print $ head . dropNaive (2^30) $ [1..]
% stack ghc -- ListTest.hs
[1 of 1] Compiling Main ( ListTest.hs, ListTest.o )
Linking ListTest ...
% time ./ListTest
1073741825
./ListTest 31.56s user 0.12s system 99% cpu 31.774 total
drop
来自GHC.List
:
% git checkout drop-ghc
% git clean --force
% cat ListTest.hs
{-# LANGUAGE BangPatterns #-}
module ListTest where
dropGhc :: Int -> [a] -> [a]
{-# INLINE dropGhc #-}
dropGhc n xs
| n <= 0 = xs
| otherwise = unsafeDrop n xs
where
unsafeDrop :: Int -> [a] -> [a]
unsafeDrop !_ [] = []
unsafeDrop 1 (_:xs) = xs
unsafeDrop m (_:xs) = unsafeDrop (m - 1) xs
% cat ListTestRunner.hs
import ListTest
main = print $ head . dropGhc (2^30) $ [1..]
% stack ghc -- ListTestRunner.hs
[1 of 2] Compiling ListTest ( ListTest.hs, ListTest.o )
[2 of 2] Compiling Main ( ListTestRunner.hs, ListTestRunner.o )
Linking ListTestRunner ...
% time ./ListTestRunner
1073741825
./ListTestRunner 35.35s user 0.14s system 99% cpu 35.591 total
答案 0 :(得分:3)
我以前犯过这个错误,所以我很怀疑...
您似乎没有在启用优化的情况下进行编译。前奏经过优化编译并链接到其中,因此当您使用前奏的drop
时,会隐式使用优化代码。本地复制(将常量从2^30
减少到2^25
之后-没有理由让自己等待那么长时间),启用优化会导致dropGhc
和序言drop
具有相同的含义时间,dropNaive
并没有明显恶化。 dropGhc
和dropNaive
之间的措词略有不同,可能会对生成的代码产生微妙的影响;我对一个人为什么会比另一个人好没有很好的直觉。
还要注意,base
是一个特殊的软件包,因为它是ghc
的构建过程的一部分,是使用其自身的构建系统而不是由Cabal像普通软件包那样构建的。正如@sjakobi在评论中指出的,there is a setting in ghc
's build configuration将base
的优化级别设置为O2
。