Возвращать определенный тип внутри 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) ]