Ошибка «Нет экземпляра для (Num [t])» в функции Коллатца - PullRequest
3 голосов
/ 02 июля 2010

Я новичок в Haskell и программировании в целом.Я пытаюсь определить функцию, которая генерирует последовательность чисел Коллатца из n .У меня есть:

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

генерирует бесконечную последовательность «1» после правильной последовательности Коллатца;однако

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

генерирует все числа Коллатца из n , кроме "1".Что я делаю не так?

Ответы [ 3 ]

6 голосов
/ 02 июля 2010

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

5 голосов
/ 02 июля 2010

только один ответ правильный, но так как вы новичок в Haskell, возможно, это более четкое объяснение. Оператор : pre ожидает значение в списке, поэтому выполнение somelist : 7 недопустимо, поскольку оно пытается ap в ожидании значения в списке. Вот почему (collatz' n) : 1 не компилируется, поскольку тип (collatz' n) представляет собой список чисел.

Попробуйте заменить : 1 на ++ [1].

0 голосов
/ 02 июля 2010

Другой способ решения этой проблемы - использование структуры Data.Sequence вместо списка. Последовательности позволяют вам «подхватить» значение (поместить значение в конец последовательности), а также более обычные «минусы» (поместить его в начало последовательности).

Другим решением для вас может быть использование 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.

Надеюсь, это поможет.

...