写完this article之后,我决定把钱放在嘴边,并开始将我以前的项目转换为使用recursion-schemes
。
有问题的数据结构是lazy kdtree。请查看explicit和implicit递归的实现。
这主要是一种简单的转换:
data KDTree v a = Node a (Node v a) (Node v a) | Leaf v a
到
data KDTreeF v a f = NodeF a f f | Leaf v a
现在,在对整个shebang进行基准测试后,我发现KDTreeF
版本比普通版本(find the whole run here)的慢两倍。
只是额外的Fix
封装器让我放慢了速度吗?我有什么可以做的吗?
cata (fmap foo algebra)
。这是好习惯吗?recursion-schemes
包。这有关系吗? https://ghc.haskell.org/trac/ghc/wiki/NewtypeWrappers
newtype Fix f = Fix (f (Fix f))
不是"免费"?
刚做了另一堆基准测试。这次我测试了树木的构造和解构。基准测试:https://dl.dropboxusercontent.com/u/2359191/2014-05-15-kdtree-bench-03.html
虽然Core输出表明中间数据结构没有完全删除,现在线性搜索占主导地位并不奇怪,KDTreeF
现在比KDTree
略快。然而,并不重要。
答案 0 :(得分:17)
我刚刚实现了树的Thing + ThingF + Base instance
变体。猜猜看......这个速度非常快。
我的印象是这一个是所有变种中最慢的。我真的应该阅读我自己的帖子......我写的行:
没有找到TreeF结构的痕迹
让数字说明一切,kdtreeu
是新变种。结果并不总是像这些情况一样清晰,但在大多数情况下,它们至少与显式递归一样快(基准中为kdtree
)。
答案 1 :(得分:1)
我没有使用递归方案,而是我自己的"手工推出" cata,ana,Fix / unFix用小语言生成(列表)和评估程序,希望找到一个与(输入,输出)对列表相匹配的程序。
根据我的经验,cata优化比直接递归更好,并提高了速度。此外,IME,ana防止了我的天真生成器导致的堆栈溢出错误,但是这种错误集中在最终列表的生成周围。
所以,我的答案是不,他们并不总是慢,但我没有看到任何明显的问题;所以他们可能只是在你的情况下慢。递归方案本身也可能没有针对速度进行优化。