简体   繁体   English

为什么“((1 + 1.0)””的类型为“ Fractional a => a”而不是“ Num a => a”?

[英]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.01 )。

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 (因为某些NumFractional ),也可能不是。 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: 因此,现在让我们尝试将foobar像这样组合:

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 . 它要求aNum类中。

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因为NumFractional超类。

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

  • Number 1 (which technically stands for fromInteger applied to the Integer value 1 ) belongs to all the types in class Num . 数字1 (在技术上代表fromInteger应用于Integer1 )属于Num类中的所有类型。
  • All the types in class 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM