我偶然发现了 Haskell 和 FP,并被这些可能性惊呆了。我内心的老数学书呆子为实际有用的目的编写幼稚的代码没有问题。然而,尽管阅读了所有内容,我仍然很难理解如何不遇到一些令人惊讶的性能瓶颈。
因此,我用幼稚的实现编写了非常短的代码,然后尝试进行一些小的更改以查看性能如何响应。这是一个我真的无法理解的例子......我写了这个函数来找到约瑟夫斯问题的解决方案,故意用一个简单的列表实现。
m = 3
n = 3000
main = putStr $ "Soldier #" ++ (show $ whosLeft [1..n]) ++ " survived...\n"
whosLeft [lucky] = lucky
whosLeft soldiers = whosLeft $ take (length soldiers -1) $ drop m $ cycle soldiers
后者的运行时间为 190 毫秒,根据 RTS,生产率为 63%。
然后我想尝试的第一件事是删除(长度士兵-1)并将其替换为递减整数。
运行时间跃升至 900 毫秒,生产力下降至 16%,并且使用的内存是上面更简单的代码的 47 倍!所以我添加了严格的评估,强制使用 Int 类型,尝试删除全局变量等,但效果不大。我只是无法理解这种放缓。
m = 3::Int
n = 3000::Int
main = putStr $ "Soldier #" ++ (show $ whosLeft n [1..n]) ++ " survived...\n"
whosLeft 1 [lucky] = lucky
whosLeft n' soldiers = n' `seq` left `seq` whosLeft (n'-1) left
where left = take (n'-1) $ drop m $ cycle soldiers
我已经筛选了与性能相关的文章和帖子,但我似乎对此一无所知。仍然是一个 Haskell 菜鸟,我一定错过了一些重要的东西......这个添加的参数(预先咀嚼的计算......)如何降低速度这么多?
PS:我知道,如果约瑟夫斯真的和 3000 名士兵在一起,他们就不需要自杀了……