我正在阅读Haskell书(http://haskellbook.com/),并陷入以下练习中:
f :: Float
f = 1.0
-- Question: Can you replace `f`'s signature by `f :: Num a => a`
Run Code Online (Sandbox Code Playgroud)
起初,我认为答案是肯定的。浮动提供了一个实例民,所以代以Num a => a一个Float值应该罚款(我想协方差这里)。
但是,这不会编译:
Could not deduce (Fractional a) arising from the literal ‘1.0’
from the context: Num a
bound by the type signature for:
f :: forall a. Num a => a
at ...
Possible fix:
add (Fractional a) to the context of
the type signature for:
f :: forall a. Num a => a
• In the expression: 1.0
In an equation for ‘f’: f = 1.0
Run Code Online (Sandbox Code Playgroud)
但是,如果我这样做,则没有问题:
f :: Fractional a => a
f = 1.0
Run Code Online (Sandbox Code Playgroud)
为什么我不能在这里使用不太具体的约束Num a => a?
UPD:
实际上,您可以将其总结为:
1.0::(Num a => a)
Run Code Online (Sandbox Code Playgroud)
与
1.0::(Fractional a => a)
Run Code Online (Sandbox Code Playgroud)
为什么第二个工作而不是第一个工作?我以为Fractional是Num(Fractional与兼容Num)的子集
UPD 2:
感谢您的评论,但我仍然感到困惑。工作原理:
f :: Num a => a -> a
f a = a
f 1.0
Run Code Online (Sandbox Code Playgroud)
而这不是:
f :: Num a => a
f = 1.0
Run Code Online (Sandbox Code Playgroud)
UPD 3: 我刚刚注意到以下几点:
f :: Num a => a
f = (1::Int)
Run Code Online (Sandbox Code Playgroud)
也不起作用。
UPD 4
据我所知,我一直在阅读所有答案/评论:
f :: Num a => a
Run Code Online (Sandbox Code Playgroud)
是Scala的等价于
def f[A: Num]: A
Run Code Online (Sandbox Code Playgroud)
这将解释为什么a调用者定义了许多提到的内容。我们可以这样写的唯一原因:
f :: Num a => a
f = 1
Run Code Online (Sandbox Code Playgroud)
是因为1键入为Num a => a。有人可以确认这个假设吗?无论如何,谢谢大家的帮助。
如果我有f :: Num a => a这意味着我可以f在需要任何数字类型的任何地方使用。因此,所有f :: Int,都f :: Double必须键入check。
在您的情况下,1.0 :: Int由于相同的原因我们不能拥有543.24 :: Int,即Int不代表小数。但是,1.0它适合任何小数类型(543.24也是)。
Fractional确实可以认为是的子集Num。但是如果我在所有小数里面都有一个值f :: forall a . Fractional a => a,我不一定在所有的数字类型中都有一个值f :: forall a . Num a => a。
请注意,从某种意义上说,约束位于的左侧=>,这使它们的行为相反。即汽车是车辆的一部分,但我不能断定可以在任何汽车中使用的车轮都可以与任何车辆一起使用。相反,相反:可以在任何车辆中使用的车轮将可以在任何汽车中使用。
所以,你可以粗略地认为f :: forall a . Num a => a(值的任何数值类型配件,喜欢3和5)作为一种亚型 f :: forall a . Fractional a => a(值的任何小数型配件,如3,5和32.43)。