(Num a)vs Integer类型推断

时间:2013-03-16 10:50:48

标签: haskell

考虑以下Haskell函数:

sign a
  | a < 0 = (-1)
  | a > 0 = 1
  | otherwise = 0

当我将其加载到ghci时,我期望:t sign为:

sign :: (Num a, Ord a) => a -> Integer

相反,它推断为:

*Main> :t sign
sign :: (Num a1, Num a, Ord a1) => a1 -> a

同样,如果我要求整数5的类型,我期望Integer,但我得到了

*Main> :t 5
5 :: Num a => a

我不了解Haskell的类型。问题是,如果我所知道的sign的返回类型是它是Num类型类的实例,那么我就不能将它的返回值传递给这个函数:

double :: Integer -> Integer
double x = x * 2

也就是说,我的double函数需要Integer,而不仅仅是Num的任何实例。

然而,以下工作正常:

*Main> double (sign 5.5)
2

我对Haskell的类型系统的误解是什么?

3 个答案:

答案 0 :(得分:19)

  

问题是,如果我所知道的'sign'的返回类型是它是Num类型类的实例,那么我就不能将它的返回值传递给这个函数:< / p>

是的,如果这就是你所知道的,你就无法将其传递给double

但是类型

sign :: (Num a1, Num a, Ord a1) => a1 -> a

表示sign的结果类型为 Num类型调用者要求。类型签名中的类型变量是(隐式)普遍量化,而不是存在,例如Java接口。

sign可以生成任意类型的返回值,受限于它是Num的实例,它返回的类型由调用上下文决定。

如果来电者需要Integer,则会获得一个。如果它想要Double,也没问题。

我最初忘了提及:

  

同样,如果我要求整数5的类型,我期望“整数”,但我得到了

    *Main> :t 5
    5 :: Num a => a

数字文字是多态的,整数文字代表fromInteger value,而fromRational value是小数文字。

答案 1 :(得分:10)

我只是想澄清@ DanielFischer的答案。像f :: Num b => a -> b这样的类型签名意味着f能够返回类型Num任何实例。调用f时,Haskell使用上下文(调用者的类型签名)来确定b的具体类型。

此外,Haskell的数字文字就是这种多态的一个例子。这就是:t 5给你Num a => a的原因。符号5能够充当任何类型的数字,而不仅仅是整数。它出现的上下文决定了它将会是什么。

答案 2 :(得分:6)

在Haskell中,如果函数返回类型x是其结果,这意味着调用者可以选择x应该是什么,而不是函数< / em>的。相反,函数必须能够返回任何可能的类型

您的sign可以返回任何类型的数据 - 包括Integerdouble函数想要一个Integer,所以没关系 - sign可以返回。{/ p>

您可能不知道的另一部分难题:在Java中,2的类型为int2.0的类型为double。但在Haskell中,2的类型为Num x => x - 换句话说,任何可能的数字类型。 (同样2.0的类型为Fractional x => x,这是类似的交易。)