繁体   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的类型为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.01 )。

每个小数都是一个Num ,但不是每个Num都是一个Fractional 因此,如果我们有一个像1这样的Num ,它可能是Fractional (因为某些NumFractional ),也可能不是。 但是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

因此,现在让我们尝试将foobar像这样组合:

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

然后我们有(+)1.0 ,这两个都还需要相同a参数。 (+)再次需要Num ,没有什么新内容; 但是1.0需要Fractional a 因此,总而言之, 1 + 1.0是一个函数,它接受类型参数a “三个副本”,并且需要

  • Num a
  • Num a
  • Fractional a –也需要Num a因为NumFractional超类。

如果我们实际上不得不将类型写为

(1 + 1.0) :: (Num a, Num a, Fractional a, Num a) => a

因此可以忽略多余的约束,只保留Fractional a ,这意味着其余所有约束。 我们不能做的只是保留Num约束之一,因为那并不意味着Fractional

  • 数字1 (在技术上代表fromInteger应用于Integer1 )属于Num类中的所有类型。
  • Fractional类中的所有类型也都属于Num类。

嗯,

1属于Fractional类中的所有类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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