长度vs折叠vs显式递归的性能特征

问题描述

我已经编写了length函数的六个版本。一些性能上的差异是合理的,但其中一些似乎根本不符合我所读的文章(例如this onethis one)。

-- len1 and lenFold1 should have equivalent performance,right?

len1 :: [a] -> Integer
len1 [] = 0
len1 (x:xs) = len1 xs + 1

lenFold1 :: [a] -> Integer
lenFold1 = foldr (\_ a -> a + 1) 0


-- len2 and lenFold2 should have equivalent performance,right?

len2 :: [a] -> Integer
len2 xs = go xs 0 where
  go [] acc = acc
  go (x:xs) acc = go xs (1 + acc)

lenFold2 :: [a] -> Integer
lenFold2 = foldl (\a _ -> a + 1) 0


-- len3 and lenFold3 should have equivalent performance,right?
-- And len3 should outperform len1 and len2,right?

len3 :: [a] -> Integer
len3 xs = go xs 0 where
  go [] acc = acc
  go (x:xs) acc = go xs $! (1 + acc)

lenFold3 :: [a] -> Integer
lenFold3 = foldl' (\a _ -> a + 1) 0

我的机器上的实际性能令人困惑。

*Main Lib> :set +m +s
*Main Lib> xs = [1..10000000]
(0.01 secs,351,256 bytes)
*Main Lib> len1 xs
10000000
(5.47 secs,2,345,244,016 bytes)
*Main Lib> lenFold1 xs
10000000
(2.74 secs,1,696,750,840 bytes)
*Main Lib> len2 xs
10000000
(6.02 secs,980,997,432 bytes)
*Main Lib> lenFold2 xs
10000000
(3.97 secs,776,816 bytes)
*Main Lib> len3 xs
10000000
(5.24 secs,3,520,354,616 bytes)
*Main Lib> lenFold3 xs
10000000
(1.24 secs,040,528 bytes)
*Main Lib> length xs
10000000
(0.21 secs,720,480 bytes)

我的问题:

  1. 为什么每个函数的fold版本都使用显式递归始终优于该版本?
  2. 尽管有this article的警告,但这些实现都没有达到我的计算机上的堆栈溢出。为什么不呢?
  3. 为什么len3的表现不比len1len2好?
  4. 为什么Prelude的length的性能要比任何这些实现​​都要好?

编辑:

由于卡尔的建议,我的第一个和第二个问题是由GHCI默认解释代码的事实解决的。使用-fobject-code再次运行它可以解决显式递归和折叠之间的不同性能。新的测量值:

Prelude Lib Main> xs = [1..10000000]
(0.00 secs,136 bytes)
Prelude Lib Main> len1 xs
10000000
(1.62 secs,612,661,544 bytes)
Prelude Lib Main> lenFold1 xs
10000000
(1.62 secs,692,552 bytes)
Prelude Lib Main> len2 xs
10000000
(2.46 secs,855,662,888 bytes)
Prelude Lib Main> lenFold2 xs
10000000
(2.53 secs,772,528 bytes)
Prelude Lib Main> len3 xs
10000000
(0.48 secs,680,361,272 bytes)
Prelude Lib Main> lenFold3 xs
10000000
(0.31 secs,240 bytes)
Prelude Lib Main> length xs
10000000
(0.18 secs,272 bytes)

我对此仍然有一些疑问。

  1. 为什么lenFold3的表现胜过len3?我跑了几次
  2. length仍然如何胜过所有这些实现?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)