[英]Why does “(1 + 1.0)” have the type “Fractional a => a” and not “Num a => a”?
1
has the type Num a => a
1
的类型为Num a => a
1.0
has the type Fractional a => a
1.0
的类型为Fractional a => a
Why does 1+1.0
have the type Fractional a => a
为什么1+1.0
的类型为Fractional a => a
This seems strange to me because 1
is not fractional. 我觉得这很奇怪,因为1
不是小数。 Only 1.0
is fractional. 只有1.0
是小数。 So how did 1
turn into fractional and get combined with 1.0
to form a fractional? 那么1
如何变成小数并与1.0
结合形成小数的呢?
Since only Num
has the + operator, it would seem more natural to me if 1.0
turned into Num
, got combined with 1
to produce a final Num
(although that would be strange too because we would lose information going from 1.0
to 1
). 由于只有Num
具有+运算符,所以对我来说,如果将1.0
转换为Num
,并与1
组合以生成最终的Num
,这似乎更自然(尽管这也很奇怪,因为我们会丢失从1.0
到1
)。
Every Fractional is a Num
, but not every Num
is a Fractional
. 每个小数都是一个Num
,但不是每个Num
都是一个Fractional
。 So if we have a Num
like 1
, it could either be a Fractional
(because some Num
s are Fractional
s) or it could not be. 因此,如果我们有一个像1
这样的Num
,它可能是Fractional
(因为某些Num
是Fractional
),也可能不是。 However 1.0
can only be a Fractional
, it definitely can't be some other Num
like Integer
. 但是1.0
只能是Fractional
,绝对不能是Integer
Num
。
So when the compiler sees that you add 1 to a Fractional
, it realizes that 1
must be a Fractional
as well in this case - otherwise you'd not be allowed to add it to a Fractional
. 因此,当编译器看到您将1加到一个Fractional
,它意识到在这种情况下1
必须是一个Fractional
-否则您将不允许将其添加到Fractional
。
Here's an example of a similar example that only involves user-defined type classes instead of Num
s. 这是一个类似示例的示例,该示例仅涉及用户定义的类型类而不是Num
。 Maybe this makes things clearer for you: 也许这会使您更清楚:
class Foo a where
foo :: a
class Foo a => Bar a where
bar :: a
combine :: a -> a -> a
Through the above type classes we now have the following methods: 通过上述类型类,我们现在具有以下方法:
foo :: Foo a => a
bar :: Bar a => a
combine :: Bar a => a -> a -> a
So now let's try to combine foo
and bar
like this: 因此,现在让我们尝试将foo
和bar
像这样组合:
combine foo bar
This is roughly equivalent to you trying to add 1
(of type Num a => a
) and 1.0
(of type Fractional a => a
) in your example. 这大致相当于您在示例中尝试添加1
(类型为Num a => a
)和1.0
(类型为Fractional a => a
)。 And just like your example, this works fine and has the type Bar a => a
. 就像您的示例一样,此方法工作正常,类型为Bar a => a
。
Type classes are very much not like OO classes, this can't be overemphasized. 类型类都非常不喜欢OO类,这一点都不为过。
In particular, “if 1.0
turned into Num
” doesn't make any sense. 特别地,“如果1.0
变成Num
”没有任何意义。 Num
is a type class, not a type, so nothing can ever “turn into a Num
”. Num
是类型类,而不是类型,因此没有任何东西可以“变成Num
”。 In fact, nothing ever turns into something else at all in Haskell – everything has a concrete type, that is fixed. 实际上,在Haskell中,没有任何东西可以变成其他东西-一切都有固定的具体类型。
Now you ask, how do polymorphic functions work then? 现在您问,多态函数如何工作? Well, it's called parametric polymorphism for a reason: what seems to be an “arbitrary type a
” is really a type parameter . 好吧,这被称为参数多态是有原因的:似乎是“任意类型a
”实际上是类型参数 。 Like a function parameter, these aren't variables in the sense that they can ever change their value after the fact, but they are variable in the sense that the caller of the function is allowed to choose any particular “type value” for a
– provided it fulfills the type-class constraint. 像一个函数的参数,这些都不是在这个意义上,他们都不能改变的事实后,其值的变量,但他们该函数的调用者被允许选择任何特定的“类型值”为在这个意义上变a
-只要它满足类型-类约束。
So in a sense, the literal 1
is a function: it accepts a type argument a
, and returns a value 1 :: a
. 因此从某种意义上说,文字1
是一个函数:它接受类型参数 a
,并返回值1 :: a
。 What it requires is that a
is in class Num
. 它要求a
在Num
类中。
Then we have (+)
and 1.0
, both of which also need that same a
argument. 然后我们有(+)
和1.0
,这两个都还需要相同a
参数。 (+)
again requires Num
, nothing new; (+)
再次需要Num
,没有什么新内容; but 1.0
requires Fractional a
. 但是1.0
需要Fractional a
。 So all in all, 1 + 1.0
is a function that accepts “three copies of” the type argument a
, and requires 因此,总而言之, 1 + 1.0
是一个函数,它接受类型参数a
“三个副本”,并且需要
Num a
Num a
Fractional a
– which also requires Num a
because Num
is superclass of Fractional
. Fractional a
–也需要Num a
因为Num
是Fractional
超类。 It would be pretty awkward if we actually had to write the type out as 如果我们实际上不得不将类型写为
(1 + 1.0) :: (Num a, Num a, Fractional a, Num a) => a
so it is allowed to leave out the redundant constraints, only leaving Fractional a
, which implies all the rest. 因此可以忽略多余的约束,只保留Fractional a
,这意味着其余所有约束。 What we can't do is only leave one of the Num
constraints, because that would not imply Fractional
. 我们不能做的只是保留Num
约束之一,因为那并不意味着Fractional
。
1
(which technically stands for fromInteger
applied to the Integer
value 1
) belongs to all the types in class Num
. 数字1
(在技术上代表fromInteger
应用于Integer
值1
)属于Num
类中的所有类型。 Fractional
belong to class Num
as well. Fractional
类中的所有类型也都属于Num
类。 Ergo, 嗯,
Number 1
belongs to all the types in class Fractional
. 1
属于Fractional
类中的所有类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.