我是Haskell的新手,也是一般的编程。我正在尝试定义一个函数,该函数从 n 生成Collatz数字序列。我有:
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))
在正确的Collatz序列之后生成无限序列的“1”;然而,
collatz' n = (takeWhile (>1) (collatz'' n))
从 n 生成所有Collatz编号,“1”除外。我做错了什么?
答案 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
表单时,这是您要查找的表单。
我希望这会有所帮助。