15

我对 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 中的类型。Double 属于此类(http://www.zvon.org/other/haskell/Outputprelude/Num_c.html),所以我原以为在这种情况下“返回” Double 是可以的。

有人可以解释一下吗?

4

3 回答 3

16

带有签名的函数Num a => a应该适用于类中的任何类型Num。该实现5.0 :: Double仅适用于一种类型,而不适用于类的所有类型,因此编译器会抱怨。

一个通用函数的例子是:

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

这适用于任何类型为Num. 它适用于双精度数、整数和您想要使用的任何其他数字。因此,它可以有一个泛型类型签名,只需要参数在 class 中Num。(类型类Num是必需的,因为该函数使用乘法与*,这是在那里定义的)

于 2009-10-07T21:25:23.337 回答
9

添加到某事的答案:Haskell 不是面向对象的。不是Double的子类Num,因此Double如果您承诺返回多态Num值,则不能返回 a ,就像在 Java 中一样。

当您编写时,getN :: Num a => a您承诺返回一个在Num约束内完全多态的值。实际上,这意味着您只能使用类型类中的函数,Num例如+、和。*-fromInteger

于 2009-10-08T08:48:41.727 回答
3

查看Existentially quantified types

解决它的一种方法是定义一个新的数据类型

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) ]
于 2009-10-12T09:10:37.473 回答