Почему Haskell интерпретирует мой тип Num как Enum? - PullRequest
2 голосов
/ 07 октября 2009

Я пытаюсь скомпилировать следующую функцию в Haskell, чтобы имитировать дифференцирование многочлена, константы которого указаны в числовом списке:

diff :: (Num a) => [a] -> [a]
diff [] = error "Polynomial unspecified"
diff coeff = zipWith (*) (tail coeff) [0..]

Хаскелл отказывается его компилировать, объясняя мне причину:

Could not deduce (Enum a) from the context (Num a)
 arising from the arithmetic sequence `0 .. ' at fp1.hs:7:38-42
Possible fix:
 add (Enum a) to the context of the type signature for `diff'
In the third argument of `zipWith', namely `[0 .. ]'
In the expression: zipWith (*) (tail coeff) ([0 .. ])
In the definition of `diff':
diff coeff = zipWith (*) (tail coeff) ([0 .. ])

Почему Haskell рассматривает список [0..] как тип Enum, и как я могу это исправить. Имейте в виду, что я хочу воспользоваться преимуществами ленивых вычислений, отсюда и бесконечный список.

Ответы [ 4 ]

8 голосов
/ 07 октября 2009

[0..] - синтаксический сахар для enumFrom 0, определенный в классе Enum. Поскольку вы хотите сгенерировать список a с [0..], компилятор требует, чтобы a находился в классе Enum.

Вы можете добавить Enum a к сигнатуре типа функции или обойти ее, сгенерировав [0..] :: [Integer] и используя fromInteger (который определен в классе Num), чтобы получить [a] из что:

diff :: (Num a) => [a] -> [a]
diff [] = error "Polynomial unspecified"
diff coeff = zipWith (*) (tail coeff) (map fromInteger [0..])
7 голосов
/ 07 октября 2009

Правильный тип diff должен быть

diff :: (Num a, Enum a) => [a] -> [a]

потому что использование [x..] требует, чтобы тип создал Enum.

3 голосов
/ 07 октября 2009

[0..] является сокращением для enumFrom 0 См. Здесь

2 голосов
/ 07 октября 2009

Вот краткое изложение того, что видит компилятор, когда смотрит на эту функцию:

  • [0 ..] - список вещей, которые имеют экземпляры Num и Enum. Это должен быть Num из-за '0', и это должен быть Enum из-за '..'
  • Меня просят применить (*) к элементам coeff и [0 ..] по одному. Поскольку оба аргумента (*) должны быть одного типа, а [0 ..] имеет экземпляр для Enum, coeff также должен иметь экземпляр для Enum.
  • Ошибка! Сигнатура типа diff только упоминает, что у coeff есть экземпляр для Num, но я уже определил, что он должен по крайней мере также иметь экземпляр для Enum.
...