问题
I am new to Haskell, and programming in general. I am trying to define a function which generates the sequence of Collatz numbers from n. I have:
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)
When I run this in GHCi, I get the error:
No instance for (Num [t])
arising from the literal `2' at <interactive>:1:7
Possible fix: add an instance declaration for (Num [t])
I don't know what this means. The problem seems to be appending "1" to the list. This problem emerges because
collatz' n = (takeWhile (>0) (collatz'' n))
generates an infinite sequence of "1"s following the correct Collatz sequence; however,
collatz' n = (takeWhile (>1) (collatz'' n))
generates all Collatz numbers from n except "1". What am I doing wrong?
回答1:
ony's answer is correct, but since you're new to Haskell, maybe this is a clearer explanation. The :
operator prepends a value to a list, so doing somelist : 7
is invalid since that's trying to append a value to a list. That's why (collatz' n) : 1
doesn't compile, since the type of (collatz' n)
is a list of numbers.
Try replacing the : 1
with ++ [1]
.
回答2:
(:) :: a -> [a] -> [a]
Your first line collatz n = (collatz' n) : 1
forces 1
to become [a]
.
I guess you wanted something like (collatz' n) ++ [1]
And you have error in if (even n) then (div n 2) else ((3*2)+1)
there should be ((3*n)+1
or something like that else you have collatz''' 7 = 7
回答3:
Another way to go at the problem may be for you to use a Data.Sequence structure instead of a list. Sequences allow you to "snoc" a value (put a value on the back of a sequence) as well as the more usual "cons" (put it on the front of the sequence).
Another solution for you may be to use span
to make your own "takeUntil" function.
Let me explain: span p xs
gives you the same answer as (takeWhile p xs, dropWhile p xs)
for whichever p
function and xs
list you'd use, the same way that splitAt n xs
is the same as (take n xs, drop n xs)
.
Anyway, you can use span
to make your own "takeUntil" function:
takeUntil p xs = taken ++ take 1 dropped where
(taken, dropped) = span p xs
This is the form that you were looking for, when you used the collatz n = (collatz' n) : 1
form.
I hope this helps.
来源:https://stackoverflow.com/questions/3163718/error-no-instance-for-num-t-in-collatz-function