我已经开始通过尝试解决一些小问题来潜入Haskell。Haskell:代码的两个版本之间的速度差
我于“标准哈斯克尔友好”解决方案,我“极丑和Haskell不友好”版本之间有很大的性能差异(〜100-200x)绊倒了。
我敢肯定,对于同性恋者来说,这种表现上的差异有一个很好的理由,我错过了,可以教我关于这个话题。
问题:查找数字串
内的最高5位数字都用在解决相同概念:产生所有5位数字,并找出最大。
优雅和快速的代码
digit5 :: String -> Int
digit5 = maximum . map (read . take 5) . init . tails
长得丑,而且速度很慢的代码(一旦字符串大小大)
digit5' :: String -> String -> String
-- xs - input string
-- maxim - current maximal value
digit5' xs maxim
| (length xs) < 5 = maxim
| y > maxim = digit5' (drop 1 xs) y -- use new detected maximum value
| otherwise = digit5' (drop 1 xs) maxim
where y = take 5 xs
digit5 :: String -> Int
digit5 xs
-- return the original string if the input size is smaller than 6
| length (xs) < 6 = read xs
| otherwise = read $ digit5' xs "00000"
对于小的投入,我得到大致相同的执行时间,对于大的投入我开始看到很大的差异(对于44550个元素的输入):
Computation time for ugly version: 2.047 sec
Computation time for nice version: 0.062 sec
我的肤浅对此的了解是,快速代码是使用预先提供的高阶功能。对于较慢的版本递归使用,但我认为咬尾应该是可能的。但在天真的水平,对我来说似乎都做同样的事情。
而较慢的功能确实比较对字符串,而不是将它们转换为数字,我也试着转换字符串整数,但没有任何大的改善
我试着使用GHC不带任何标志,并与编译下面的命令:
ghc
ghc -O2
ghc -O2 -fexcess-precision -optc-O3 -optc-ffast-math -no-
recomp
stack runhaskell
ghc -O3
对于重复性我加入的链接代码contaning也测试向量的缘故:https://pastebin.com/kuS5iKgd
您有递归地在一个列表,并调用函数'length'在每一次迭代。长度是O(n)。您不小心向运行时添加了O(n^2)项。 – Carl
只是跳过警卫'|长度为xs <5 = maxim'为额外的模式'digit5'[] maxim = maxim'给我0.004秒而不是1.7秒。这比优雅的解决方案还要快。 (读取总是会消耗部分字符串的5个字节,而字符串比较可能只需要比较第一个字符)。 – Krom