【发布时间】:2018-03-07 00:48:40
【问题描述】:
维基百科写到Hylomorphism:
在 [...] 函数式编程中,hylomorphism 是递归的 函数,对应于变形的组合(其中 首先构建一组结果;也称为“展开”)随后 通过变态(然后将这些结果折叠成最终的回报 价值)。将这两个递归计算融合为一个 递归模式然后避免构建中间数据 结构。这是森林砍伐的一个例子,一个程序 优化策略。
(我的粗体标记)
使用recursion-schemes 库 我写了一个很简单的hylomorphism:
import Data.Functor.Foldable
main :: IO ()
main = putStrLn $ show $ hylosum 1000
hylosum :: Int -> Int
hylosum end = hylo alg coalg 1
where
-- Create list of Int's from 1 to n
coalg :: Int -> ListF Int Int
coalg n
| n > end = Nil
| otherwise = Cons n (n + 1)
-- Sum up a list of Int's
alg :: ListF Int Int -> Int
alg Nil = 0
alg (Cons a x) = a + x
在 cabal 文件中我指示 GHC 优化代码:
name: Hylo
version: 0.1.0.0
synopsis: Hylomorphisms and Deforestation
build-type: Simple
cabal-version: >=1.10
executable Hylo
main-is: Main.hs
ghc-options: -O2
build-depends: base >=4.10 && <4.11 , recursion-schemes
default-language: Haskell2010
使用堆栈 lts-10.0 (GHC 8.2.2) 我使用 stack build 编译并使用 stack exec Hylo -- +RTS -s 运行,我得到:
500500
84,016 bytes allocated in the heap
3,408 bytes copied during GC
44,504 bytes maximum residency (1 sample(s))
25,128 bytes maximum slop
2 MB total memory in use (0 MB lost due to fragmentation)
现在我将hylosum 1000 更改为hylosum 1000000(1000 倍以上),我得到:
500000500000
16,664,864 bytes allocated in the heap
16,928 bytes copied during GC
15,756,232 bytes maximum residency (4 sample(s))
29,224 bytes maximum slop
18 MB total memory in use (0 MB lost due to fragmentation)
因此堆使用量从 84 KB 上升到 16,664 KB。这比以前多了200倍。 因此我认为,GHC 不会做维基百科中提到的森林砍伐/融合!
这并不奇怪:变形从左到右创建列表项 (从 1 到 n)并且 catamorphism 从右到左以相反的方式消耗物品 (从 n 到 1)并且很难看出 hylomorphism 是如何工作的 无需创建整个中间列表。
问题: GHC 是否能够执行森林砍伐? 如果是,我需要在我的代码或 cabal 文件中进行哪些更改? 如果是,它是如何真正起作用的? 如果否,问题出在哪里:维基百科、GHC 还是图书馆?
【问题讨论】:
-
TL;DR 这并不是自动发生的:有时 GHC 的内联就足够了,但通常你需要一些重写规则。
-
@Alec:所以hylo函数的每个用户都必须自己编写这些重写规则?这些重写规则对我的情况如何?
标签: haskell ghc recursion-schemes