我试图解决一些小问题,开始潜入Haskell。
我偶然发现"标准的haskell友好型" 解决方案和我的"之间存在巨大的性能差异(~100-200x)。非常丑陋且不耐烦的" 版本。
我确信对于其他的haskellers来说,这种性能上的差异有一个很好的理由,我很遗憾,并且可以就这个话题教育我。
问题:查找数字字符串中的最大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
为了重现性,我还添加了一个代码链接,同时还包含测试向量:https://pastebin.com/kuS5iKgd