TL; DR:这不是Num a => a
一个值Num
,而是一个可以是任何类型的值的定义Num
,无论该类型是什么,具体而言,由使用它的每个特定位置确定。
我们先定义它,然后再使用它。
如果我们已经对它进行了一般定义,以便它可以用于许多不同的特定类型,我们以后可以在许多不同的使用站点使用它,每个站点都需要我们的定义为其提供特定类型的值。只要该特定类型符合定义和使用站点的类型约束。
这就是多态定义的意义所在。
它不是一个多态值。这是来自动态世界的概念,但我们的概念是静态的。Haskell 中的类型不是在运行时决定的。他们是众所周知的。
这是发生的事情:
> numfunc :: Num a => a -> a; numfunc = undefined
> fraval :: Fractional a => a; fraval = undefined
> :t numfunc fraval
numfunc fraval :: Fractional a => a
numfunc
要求它的论点在Num
. fraval
是一个多态定义,能够提供Fractional
特定用途可能要求的任何类型的数据。不管是什么,既然是 in Fractional
,就保证也是 in Num
,所以是可以接受的numfunc
。
由于我们现在知道它a
是 in Fractional
(因为fraval
),所以现在整个应用程序的类型也已知是 in Fractional
(因为 的类型numfunc
)。
从技术上讲,
fraval :: Fractional a => a -- can provide any Fractional
numfunc :: Num a => a -> a -- is able to process a Num
-------------------------------------------------
numfunc fraval :: (Num a, Fractional a) => a -- can provide a Fractional
并(Num a, Fractional a)
简化为类型类的交集,即Fractional a
.
这当然意味着,如果代码的其余部分没有其他内容,进一步指定类型,我们将得到一个模棱两可的类型错误(除非某些类型默认启动)。但可能有。现在这是可以接受的,并且有一个类型——多态类型,意思是,其他东西必须在代码的其余部分的某个地方,在它出现的任何特定使用站点上进一步指定它。所以现在,作为一个通用的多态定义,这是完全可以接受的。
下一个,
> frafunc :: Fractional a => a -> a; frafunc = undefined
> numval :: Num a => a; numval = undefined
> :t frafunc numval
frafunc numval :: Fractional a => a
frafunc
要求其类型为 in Fractional
。numval
能够提供所需的任何类型的数据,只要该类型在Num
. 因此,满足对某种价值的任何需求是非常高兴Fractional
的。当然,代码中的其他内容必须进一步专门化类型,但无论如何。现在一切都很好。
从技术上讲,
numval :: Num a => a -- can provide any Num
frafunc :: Fractional a => a -> a -- is able to process a Fractional
-------------------------------------------------
frafunc numval :: (Num a, Fractional a) => a -- can provide any Fractional
(我发布这个答案是因为我认为最简单的事情可能是初学者的绊脚石,而这些最简单的事情甚至可以被专家认为是理所当然的。俗话说,我们不知道谁发现了水,但它肯定不是鱼。)