Возвращать определенный тип внутри Haskell

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

getN :: Num a => a
getN = 5.0 :: Double

Когда я пытаюсь скомпилировать это, я получаю следующую ошибку:

Couldn't match expected type `a' against inferred type `Double'
  `a' is a rigid type variable bound by
      the type signature for `getN' at Perlin.hs:15:12
In the expression: 5.0 :: Double
In the definition of `getN': getN = 5.0 :: Double

Как я понимаю, функция настроена на "возврат" типа в классе Num. Двойной в этом классе (http://www.zvon.org/other/haskell/Outputprelude/Num_c.html), поэтому я ожидал, что было бы нормально "вернуть" Double в этом случае.

Может кто-нибудь объяснить это, пожалуйста?

Ответы

Ответ 1

Ожидается, что функция с сигнатурой Num a => a будет работать для любого типа в классе Num. Реализация 5.0 :: Double работает только для одного типа, а не для всех типов класса, поэтому компилятор жалуется.

Примером общей функции может быть:

square :: (Num a) => a -> a
square x = x * x

Это работает для любого типа Num. Он работает для удвоений, целых чисел и любых других чисел, которые вы хотите использовать. Из-за этого он может иметь подпись общего типа, которая просто требует, чтобы параметр находился в классе Num. (Тип type Num необходим, потому что функция использует умножение с *, которое определено там)

Ответ 2

Чтобы добавить к ответу: Haskell не является объектно-ориентированным. Неверно, что Double является подклассом Num, поэтому вы не можете вернуть Double, если вы обещаете вернуть полиморфное значение Num, как вы можете, например, в Java.

Когда вы пишете getN :: Num a => a, вы обещаете вернуть значение, полностью полиморфное в пределах ограничения Num. Это означает, что вы можете использовать только функции класса Num типа +, *, - и fromInteger.

Ответ 3

Вычислить типы с количественным определением.

Один из способов его решения - определить новый тип данных

data NumBox = forall n. Num n => NumBox n

Вам понадобится -XExistentialQuantification, чтобы заставить это работать.

Теперь вы можете написать что-то вроде

getN :: NumBox
getN = NumBox (5.0 :: Double)

Вы также можете определить NumBox -list как

let n3 = [NumBox (4.0 :: Double), NumBox (1 :: Integer), NumBox (1 :: Int) ]