在 Haskell 中查找长 Collat​​z 序列

Finding long Collatz sequences in Haskell

今天,我在 Haskell ...

中玩 Collat​​z 序列

这是我的代码:

collatzLength :: Int -> Integer -> Int
collatzLength count 1 = count
collatzLength count n = collatzLength (count+1) $ if n `mod` 2 == 0 then n `div` 2 else 3*n+1

main =
    print (collatzLength 1 (10^10000 + 1))

我想做的是在 [1, 3 ..] 上无限迭代。每次找到新的最大 Collat​​z 长度时,我都想在屏幕上显示它,然后继续。我不知道如何在 Haskell 中执行此操作,因为我必须在某处保留和更新最大长度值。

使用map和无限范围

main = print $ map (collatzLength 1) [1,3..]

或使用显式递归

main :: IO ()
main = loop 1

loop :: Int -> IO ()
loop n = do
   print (collatzLength 1 n)
   loop (n+2)

后一种方法可以让您更好地控制循环。

请注意,每个循环都会从头开始计算序列号,而不会利用之前计算的结果。要获得更有效的方法,请查找 memoization(不要与 "memorization" 混淆)。这种技术允许程序 "remember" 以前计算的递归调用的结果,这样新的调用就不必重新计算相同的值。

如果要保留所有返回值的最大值,可以使用

loop :: Int -> Int -> IO ()
loop n prevMax = do
   let m = collatzLength 1 n
   putStrLn $ "collatzLength 1 " ++ show n ++ " = " ++ show m
   let nextMax = max prevMax m
   putStrLn $ "current maximum = " ++ show nextMax
   loop (n+2) nextMax

But I do not want to print all the results. Only the lengths that are higher than the "current" maximum length.

然后,生成那些 "higher" 点的列表:

-- Assumes a list of positive numbers.
-- Returns the list of those elements which are larger than all the
-- previous ones.
highPoints :: [Int] -> [Int]
highPoints xs = go 0 xs
   where
   go :: Int -> [Int] -> [Int]
   go _          []     = []
   go currentMax (n:ns) | n > currentMax = n : go n ns
                        | otherwise      = go currentMax ns

main :: IO ()
main = do 
   let collatzSequence :: [Int]
       collatzSequence = map (collatzLength 1) [1,3..]
   print (highPoints collatzSequence)