2015-02-07 108 views
1

1有型Num a => a为什么“(1 + 1.0)”的类型是“分数a => a”而不是“数字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)。

回答

3

类型类非常多不是像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因为NumFractional超。

如果我们真的不得不写类型出来作为

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

因此被允许离开了冗余约束,只留下Fractional a,这意味着所有的其他人来说将是非常尴尬的。我们不能做的只是留下Num的限制之一,因为这并不意味着Fractional

9

每个小数是Num,但不是每个NumFractional。因此,如果我们有Num1,它可能是Fractional(因为某些Num s是Fractional s)或它不可能。但1.0只能是Fractional,它绝对不能是其他一些NumInteger

所以当编译器看到您添加1至Fractional,它意识到1必须是Fractional以及在这种情况下 - 否则,你会不会被允许将其添加到Fractional


这里的一个类似的例子,只有涉及用户定义的类型的类,而不是Num S的一个例子。也许这使事情变得更清晰你:

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

+0

你写道:“所以如果我们有一个数字为1的数字,它可以是分数(因为有些数字是分数),或者它不可能是。好的,但问题是,你怎么知道1可以是分数?这是一个合法的问题,因为你告诉我,1可以是或不是分数。在这里发生了一些有关Num的特殊魔法,Haskell有特殊的对待,或者这是关于类型和函数的更一般的东西?请详细说明。 – stackoverflowuser 2015-02-07 18:43:16

+1

@stackoverflowuser直接从语句“每个小数是一个数字”,我们知道这是因为“小数”被定义为'类数量a =>小数a其中...'。 – sepp2k 2015-02-07 18:56:25

+0

这对我来说没有意义。 “每个分数都是数字”告诉你每个分数都是一个数字,而不是每个数字都是一个分数。 1是Num。我现在很困惑。换句话说:假设我创建了自己的类型,它是Num的一个实例。这种类型的值如何成为分数?靠魔术?也许Haskell在1的情况下做了一些特殊的魔术,它不适用于我自己的Num类型的值? – stackoverflowuser 2015-02-07 20:26:39

2
  • 1(这在技术上代表fromInteger施加到Integer1)属于所有类型中Num类。
  • Fractional类中的所有类型都属于Num类。

人机工程学,

1属于所有类型Fractional类。

+0

'1 :: Num a => a',所以不会隐式调用'fromInteger 1'。自从'(+ 1.0):: Fractional a => a - > a'以来,编译器在调用站点将'1'的类型细化为'Fractional a => a'。 – acomar 2015-02-07 19:25:23

+2

@acomar有一个隐式调用'fromInteger',这就是为什么'1'可以有'Num a => a'类型的原因。 – sepp2k 2015-02-07 20:27:46

+0

@ sepp2k:这意味着'1 :: Integer'或类似的东西,以便转换为'Num a => a'。你会如何观察这样的事情? – acomar 2015-02-07 20:41:39

相关问题