从1到n的所有Collat​​z序列的列表

时间:2014-07-27 21:18:31

标签: haskell

我试图编写一个函数来计算从1到n的所有数字的Collat​​z序列。结果应该是列表清单的形式。

这样的事情:

collatzSeqs 5 => [[1], [2, 1], [3, 10, 5, 16, 8, 4, 2, 1], [4, 2, 1], [5, 16, 8, 4, 2, 1]] 

我的代码如下所示:

nextCollatz:: Int-> Int
nextCollatz n 
 | n < 1 = error "number lower than 1"
 | n == 1 = 1
 | mod n 2 == 0 = div n 2
 | otherwise =  3 * n + 1 -- Calculates the next Collatz number


collatzSeq:: Int-> [Int] 
collatzSeq n
 | n < 1 = error "number lower than 1"
 | n == 1 = [1]
 | otherwise = n:collatzSeq (nextCollatz n) -- Makes a sequence a collatz sequence

我必须编写collatzSeqs的想法是采用head[collatzSeq]并以某种方式继续以递归形式执行它,然后获取结果并将其插入可能为空的新列表中。

为了说明我的想法,我试图将其编码:(它没有用)

collatzSeqs :: [Int] -> [[Int]]
collatzSeqs n = collatzSeq head[1..n]: []

2 个答案:

答案 0 :(得分:2)

查看您对collatzSeqs的尝试,我们看到它需要输入n并返回包含数字1的列表列表。这源于这里实际上没有递归调用的事实。所有函数都是一个整数,并将1个consed的collat​​z序列返回到一个空列表中,如下所示:

-- example 3:
collatzSeqs 3 = collatzSeq (head [1..n]) : [] = collatzSeq 1 : [] = [1] : [] = [[1]]

我们可以看到,对于任何输入,该函数将只返回[[1]]。问题是这里没有递归。如果我们要重写这个函数,我们会得到这样的结果:

collatzSeqs n = collatzHelp n 1
  where
    collatzHelp n m
      | n == m = collatzSeq n : []
      | otherwise = collatzSeq m : collatzHelp n (m+1)

但这是复杂的方法,显然必须有一些更简单的东西,因为我们想做的只是取一个函数并将它应用于列表中的每个元素。幸运的是,确实存在!

您的collatzSeqs实际上只是一张简单的地图:

collatzSeqs n = map collatzSeq [1..n]

map是一个函数,它接受函数和列表,并返回应用于给定列表的每个元素的函数的结果列表。您可以想象它的定义如下:

map f [] = []
map f (x:xs) = f x : map f xs

在这种情况下,我们希望为每个元素计算的函数是collatzSeq,我们的列表应该是从1到n的数字,因为我们希望函数应用于包含1和n之间的每个数字。

答案 1 :(得分:0)

通过结打结。

import Control.Applicative ((<*>))
import Control.Monad (forM_)

collatz' :: [[Integer]]
collatz' = map ((:) <*> next) [1..]
 where
    next n = collatz . fromInteger $ case n `quotRem` 2 of
     (d, 0) -> d
     (_, 1) -> 3 * n + 1

collatz :: Int -> [Integer]
collatz = (collatz' !!) . pred

main :: IO ()
main = do
    nStr <- getLine
    let n = read nStr
    forM_ [1..n] $ \i -> do
        putStr $ show i
        putStr ": "
        putStr . show . take n $ collatz i
        putStrLn "..."

它只计算一次Integer的Collat​​z后继。

不会将序列停在1,而是循环,这就是take的原因。重构为1停止作为练习。