Возврат определенного типа в Haskell - PullRequest
14 голосов
/ 08 октября 2009

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

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. Double находится в этом классе (http://www.zvon.org/other/haskell/Outputprelude/Num_c.html),, поэтому я ожидал бы, что в этом случае было бы хорошо "вернуть" Double.

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

Ответы [ 3 ]

15 голосов
/ 08 октября 2009

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

Примером универсальной функции будет:

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

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

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

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

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

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

Проверить Существенно количественно определенные типы .

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

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

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

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

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

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

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