简体   繁体   English

为什么这个Haskell表达式如此之慢?

[英]Why is this Haskell expression so slow?

I'm working on Project Euler Problem 14. Here's my solution. 我正在研究Project Euler Problem 14.这是我的解决方案。

import Data.List

collatzLength :: Int->Int
collatzLength 1 = 1
collatzLength n | odd n = 1 + collatzLength (3 * n + 1)
                | even n = 1 + collatzLength (n `quot` 2)

maxTuple :: (Int, Int)->(Int, Int)->Ordering
maxTuple (x1, x2) (y1, y2)  | x1 > y1 = GT
                | x1 < y1 = LT
                | otherwise = EQ

I'm running the following out of GHCi 我正在运行以下GHCi

maximumBy maxTuple [(collatzLength x, x) | x <- [1..1000000]]

I know that if Haskell evaluated strictly, the time on this would be something like O(n 3 ). 我知道如果Haskell严格评估,那么这个时间就像O(n 3 )。 Since Haskell evaluates lazily though, it seems like this should be some constant multiple of n. 由于Haskell懒惰地评估,看起来这应该是n的一些常数倍。 This has been running for nearly an hour now. 这已经运行了近一个小时了。 Seems very unreasonable. 似乎很不合理。 Does anyone have any idea why? 有谁知道为什么?

You're assuming that the collatzLength function will be memoized. 您假设collatzLength函数将被记忆。 Haskell does not do automatic memoization. Haskell不进行自动记忆。 You'll need to do that yourself. 你需要自己做。 Here's an example using the data-memocombinators package. 这是使用data-memocombinators包的示例。

import Data.List
import Data.Ord
import qualified Data.MemoCombinators as Memo

collatzLength :: Integer -> Integer
collatzLength = Memo.arrayRange (1,1000000) collatzLength'
  where
    collatzLength' 1 = 1
    collatzLength' n | odd n  = 1 + collatzLength (3 * n + 1)
                     | even n = 1 + collatzLength (n `quot` 2)

main = print $ foldl1' max $ [(collatzLength n, n) | n <- [1..1000000]]

This runs in about 1 second when compiled with -O2 . 当使用-O2编译时,这将在大约1秒内运行。

For being able to find a maximum of a list, the whole list needs to be evaluated. 为了能够找到最大列表,需要评估整个列表。

So it will calculate collatzLength from 1 to 1000000 and collatzLength is recursive. 所以它将从11000000计算collatzLength并且collatzLength是递归的。 The worst thing is, that your definition of collatzLength is even not tail-recursive. 最糟糕的是,你对collatzLength的定义甚至不是尾递归的。

cL is short for collatzLength cLcollatzLength

cL!!n stands for collatzLength n cL!!n代表collatzLength n

cL :: [Int]
cL = 1 : 1 : [ 1 + (if odd n then cL!!(3*n+1) else cL!!(n `div` 2)) | n <- [2..]]

Simple test: 简单测试:

ghci> cL !! 13
10

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM