2010-07-02 29 views
3

我是Haskell的新手,并且一般编程。我试图定义一个函数,它可以从n生成Collat​​z数字的序列。我有:错误“Collat​​z函数中没有(Num [t])”的实例

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)) 

Ñ生成除 “1” 在Collat​​z号码。我究竟做错了什么?

回答

5

ONY的答案是正确的,但因为你是新来的Haskell,也许这是更清楚的解释。 :运算符将值挂起到列表中,因此somelist : 7无效,因为它正在尝试 ap将值挂起到列表中。这就是为什么(collatz' n) : 1不能编译的原因,因为(collatz' n)的类型是一个数字列表。

尝试用++ [1]代替: 1

+0

'(collat​​z'n):[]'很好。它会产生类似于[[a]]的东西(实际上原始的例子是编译的,但是对于第一个参数'a'没有类型绑定可以满足类限制:'collat​​z ::(Integral a,Num [[a] ])=> a - > [[a]]')。问题是任何数字(即'1')只能编译成满足类“数字a”的数据值。 – ony 2010-07-02 07:01:54

+0

也谢谢:为了强制(:)工作,我已经重写了以前的所有函数。你为我节省了很多时间! – danportin 2010-07-02 07:04:14

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

+0

谢谢:这是有道理的,并澄清(:)为我。 – danportin 2010-07-02 07:02:19

0

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

您的另一个解决方案可能是使用span来创建您自己的“takeUntil”功能。

让我解释一下:span p xs给你相同的答案(takeWhile p xs, dropWhile p xs)无论哪个p功能和xs列表中,您会使用,同样的方式,splitAt n xs相同(take n xs, drop n xs)

无论如何,你可以使用span使自己的“takeUntil”功能:

takeUntil p xs = taken ++ take 1 dropped where 
       (taken, dropped) = span p xs 

这是你要找的人,当你使用collatz n = (collatz' n) : 1表格的形式。

我希望这会有所帮助。