错误“Collat​​z功能中没有(Num [t])的实例”

时间:2010-07-02 06:39:32

标签: haskell list collatz

我是Haskell的新手,也是一般的编程。我正在尝试定义一个函数,该函数从 n 生成Collat​​z数字序列。我有:

collatz n = (collatz' n) : 1
   where collatz' n = (takeWhile (>1) (collatz'' n))
          where collatz'' n = n : collatz'' (collatz''' n)
                 where collatz''' 1 = 1
                       collatz''' n = if (even n) then (div n 2) else ((3*2)+1)

当我在GHCi中运行时,我收到错误:

No instance for (Num [t])
  arising from the literal `2' at <interactive>:1:7
Possible fix: add an instance declaration for (Num [t])

我不知道这意味着什么。问题似乎是在列表中追加“1”。出现这个问题是因为

collatz' n = (takeWhile (>0) (collatz'' n))

在正确的Collat​​z序列之后生成无限序列的“1”;然而,

collatz' n = (takeWhile (>1) (collatz'' n))

n 生成所有Collat​​z编号,“1”除外。我做错了什么?

3 个答案:

答案 0 :(得分:6)

(:) :: a -> [a] -> [a]
第一行collatz n = (collatz' n) : 1强制1成为[a] 我想你想要像(collatz' n) ++ [1]一样的东西 并且您在if (even n) then (div n 2) else ((3*2)+1)中有错误应该有((3*n)+1或类似的其他内容collatz''' 7 = 7

答案 1 :(得分:5)

ony的回答是正确的,但既然你是Haskell的新手,也许这是一个更清晰的解释。 :运算符 pre 将值与列表挂起,因此执行somelist : 7无效,因为它正在尝试 ap 将值挂起到列表中。这就是(collatz' n) : 1无法编译的原因,因为(collatz' n)的类型是数字列表。

尝试将: 1替换为++ [1]

答案 2 :(得分:0)

解决问题的另一种方法可能是使用Data.Sequence结构而不是列表。序列允许您“snoc”一个值(在序列的背面放置一个值)以及更常见的“cons”(将它放在序列的前面)。

另一种解决方案可能是使用span制作您自己的“takeUntil”功能。

让我解释一下:span p xs(takeWhile p xs, dropWhile p xs)提供与您使用的p函数和xs列表相同的答案,与{{1}相同}}与splitAt n xs相同。

无论如何,您可以使用(take n xs, drop n xs)制作自己的“takeUntil”功能:

span

当您使用takeUntil p xs = taken ++ take 1 dropped where (taken, dropped) = span p xs 表单时,这是您要查找的表单。

我希望这会有所帮助。