我最近正在探索递归方案,并希望找到一些组织同构的用例——我认为加泰罗尼亚数字可能是一个有趣的用例(我知道有更好的方法来实现加泰罗尼亚数字,这不是重点问题)。我想出的是以下内容:
import Control.Comonad.Cofree
import Control.Monad
import Data.Foldable
import Data.Function.Memoize (memoFix)
import Data.Functor.Foldable
import GHC.Natural
type Nat = Natural
-- unrelated lines omitted
catalanHisto :: Nat -> Nat
catalanHisto = histo \case
Nothing ->
1
Just fs ->
let xs = toList fs -- this is line 101 in my original code.
ys = reverse xs
in sum $ zipWith (*) xs ys
catalanMemo :: Integer -> Integer
catalanMemo = memoFix \q n ->
if n == 0
then 1
else
let xs = fmap q [0 .. n -1]
ys = reverse xs
in sum $ zipWith (*) xs ys
main :: IO ()
main = do
-- print $ catalanMemo 1000
print $ catalanHisto 1000
然而,性能会受到影响catalanHisto
:
real 49.36s
user 416.48s
sys 99.38s
与以下相比,这非常糟糕catalanMemo
:
real 0.84s
user 5.09s
sys 2.08s
鉴于至少它终止了,该histo
版本肯定记住了一些东西,但是我不确定我是否在滥用巨大的开销histo
,或者这只是以这种方式编写程序的代价。当我继续进行一些基本的分析时:
Sat Feb 19 22:58 2022 Time and Allocation Profiling Report (Final)
demo +RTS -N -s -p -RTS
total time = 20.78 secs (52462 ticks @ 1000 us, 24 processors)
total alloc = 122,870,767,920 bytes (excludes profiling overheads)
COST CENTRE MODULE SRC %time %alloc
catalanHisto.\ Catalan src/Catalan.hs:(101,5)-(103,31) 68.0 71.5
foldMap.go Control.Comonad.Cofree src/Control/Comonad/Cofree.hs:301:5-46 28.4 25.0
catalanHisto Catalan src/Catalan.hs:(97,1)-(103,31) 1.7 0.0
catalanHisto.\.ys Catalan src/Catalan.hs:102:9-23 1.3 3.3
不是解释这些结果的专家,我猜除了 中的一些分配之外Control.Comonad.Cofree
,它花费大部分时间在 的非平凡分支中进行分配catalanHisto
,可能是由于toList
and reverse
,我不确定有多少优化空间.