[英]Why does “(1 + 1.0)” have the type “Fractional a => a” and not “Num a => a”?
1
的类型为Num a => a
1.0
的类型为Fractional a => a
为什么1+1.0
的类型为Fractional a => a
我觉得这很奇怪,因为1
不是小数。 只有1.0
是小数。 那么1
如何变成小数并与1.0
结合形成小数的呢?
由于只有Num
具有+运算符,所以对我来说,如果将1.0
转换为Num
,并与1
组合以生成最终的Num
,这似乎更自然(尽管这也很奇怪,因为我们会丢失从1.0
到1
)。
每个小数都是一个Num
,但不是每个Num
都是一个Fractional
。 因此,如果我们有一个像1
这样的Num
,它可能是Fractional
(因为某些Num
是Fractional
),也可能不是。 但是1.0
只能是Fractional
,绝对不能是Integer
Num
。
因此,当编译器看到您将1加到一个Fractional
,它意识到在这种情况下1
必须是一个Fractional
-否则您将不允许将其添加到Fractional
。
这是一个类似示例的示例,该示例仅涉及用户定义的类型类而不是Num
。 也许这会使您更清楚:
class Foo a where
foo :: a
class Foo a => Bar a where
bar :: a
combine :: a -> a -> a
通过上述类型类,我们现在具有以下方法:
foo :: Foo a => a
bar :: Bar a => a
combine :: Bar a => a -> a -> a
因此,现在让我们尝试将foo
和bar
像这样组合:
combine foo bar
这大致相当于您在示例中尝试添加1
(类型为Num a => a
)和1.0
(类型为Fractional a => a
)。 就像您的示例一样,此方法工作正常,类型为Bar a => a
。
类型类都非常不喜欢OO类,这一点都不为过。
特别地,“如果1.0
变成Num
”没有任何意义。 Num
是类型类,而不是类型,因此没有任何东西可以“变成Num
”。 实际上,在Haskell中,没有任何东西可以变成其他东西-一切都有固定的具体类型。
现在您问,多态函数如何工作? 好吧,这被称为参数多态是有原因的:似乎是“任意类型a
”实际上是类型参数 。 像一个函数的参数,这些都不是在这个意义上,他们都不能改变的事实后,其值的变量,但他们该函数的调用者被允许选择任何特定的“类型值”为在这个意义上变a
-只要它满足类型-类约束。
因此从某种意义上说,文字1
是一个函数:它接受类型参数 a
,并返回值1 :: a
。 它要求a
在Num
类中。
然后我们有(+)
和1.0
,这两个都还需要相同a
参数。 (+)
再次需要Num
,没有什么新内容; 但是1.0
需要Fractional a
。 因此,总而言之, 1 + 1.0
是一个函数,它接受类型参数a
“三个副本”,并且需要
Num a
Num a
Fractional a
–也需要Num a
因为Num
是Fractional
超类。 如果我们实际上不得不将类型写为
(1 + 1.0) :: (Num a, Num a, Fractional a, Num a) => a
因此可以忽略多余的约束,只保留Fractional a
,这意味着其余所有约束。 我们不能做的只是保留Num
约束之一,因为那并不意味着Fractional
。
1
(在技术上代表fromInteger
应用于Integer
值1
)属于Num
类中的所有类型。 Fractional
类中的所有类型也都属于Num
类。 嗯,
1
属于Fractional
类中的所有类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.