初学haskell
最近学习 haskell ,在 Real world Haskell第三章 中有个作业,自己实现一个对list求长度的函数。这个问题还真不简单。
import Data.List
myLength0 :: [a] -> Integer
myLength0 [] = 0
myLength0 (a:x) = 1 + myLength0 x
h :: [a] -> Integer -> Integer
h [] l = l
h (x:xs) l = h xs $! (l + 1)
myLength1 :: [a] -> Integer
myLength1 x = h x 0
h2 :: [a] -> Integer -> Integer
h2 [] l = l
h2 (_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:xs) l = h xs $! (l + 128)
h2 (_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:xs) l = h xs $! (l + 64)
h2 (_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:xs) l = h xs $! (l + 32)
h2 (_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:xs) l = h xs $! (l + 16)
h2 (x:xs) l = h xs $! (l + 1)
myLength2 x = h2 x 0
myLength3 = foldl' (\acc x -> 1+acc) 0
我实现了这几个版本,和标准库的length比较了下,列表长度小不成问题,大了就很是问题了。
Prelude> :load exe1.hs
[1 of 1] Compiling Main ( exe1.hs, interpreted )
Ok, modules loaded: Main.
*Main> :set +s
*Main> length [1..100000]
100000
(0.03 secs, 17766888 bytes)
*Main> myLength0 [1..100000]
100000
(0.11 secs, 26769752 bytes)
*Main> myLength1 [1..100000]
100000
(0.08 secs, 29063752 bytes)
*Main> myLength2 [1..100000]
100000
(0.08 secs, 29064112 bytes)
*Main> myLength3 [1..100000]
100000
(0.03 secs, 13454440 bytes)
*Main> length [1..1000000]
1000000
(0.04 secs, 81961776 bytes)
*Main> myLength3 [1..1000000]
1000000
(0.16 secs, 114081320 bytes)
*Main> myLength2 [1..1000000]
1000000
(0.62 secs, 273896592 bytes)
*Main> myLength1 [1..1000000]
1000000
(0.63 secs, 273926760 bytes)
*Main> myLength0 [1..1000000]
1000000
(0.81 secs, 244863248 bytes)
*Main> length [1..10000000]
10000000
(0.26 secs, 802130896 bytes)
*Main> myLength3 [1..10000000]
10000000
(1.33 secs, 1122263992 bytes)
*Main> myLength2 [1..10000000]
10000000
(6.08 secs, 2722202704 bytes)
*Main> myLength1 [1..10000000]
10000000
(6.06 secs, 2722204664 bytes)
*Main> myLength0 [1..10000000]
10000000
(8.27 secs, 2427160704 bytes)
*Main> length [1..100000000]
100000000
(2.40 secs, 8002282840 bytes)
*Main> myLength3 [1..100000000]
100000000
(13.18 secs, 11202258200 bytes)
*Main> myLength2 [1..100000000]
100000000
(60.28 secs, 27202440376 bytes)
*Main> myLength1 [1..100000000]
100000000
(60.60 secs, 27201891056 bytes)
*Main> myLength0 [1..100000000]
*** Exception: stack overflow
已经解决的问题:
- 堆栈溢出 ( myLength0 )
- 不正确的尾递归优化
- 懒求值的副作用
没有解决的问题:
- 怎样才能和内置的length函数一样快?
参考