Haskell类型替换

Fra*_*oth 1 haskell

我正在阅读Haskell书(http://haskellbook.com/),并陷入以下练习中:

f :: Float
f = 1.0

-- Question: Can you replace `f`'s signature by `f :: Num a => a`
Run Code Online (Sandbox Code Playgroud)

起初,我认为答案是肯定的。浮动提供了一个实例民,所以代以Num a => a一个Float值应该罚款(我想协方差这里)。

但是,这不会编译:

Could not deduce (Fractional a) arising from the literal ‘1.0’
      from the context: Num a
        bound by the type signature for:
                   f :: forall a. Num a => a
        at ...
      Possible fix:
        add (Fractional a) to the context of
          the type signature for:
            f :: forall a. Num a => a
    • In the expression: 1.0
      In an equation for ‘f’: f = 1.0
Run Code Online (Sandbox Code Playgroud)

但是,如果我这样做,则没有问题:

f :: Fractional a => a
f = 1.0
Run Code Online (Sandbox Code Playgroud)

为什么我不能在这里使用不太具体的约束Num a => a

UPD

实际上,您可以将其总结为:

1.0::(Num a => a)
Run Code Online (Sandbox Code Playgroud)

1.0::(Fractional a => a)
Run Code Online (Sandbox Code Playgroud)

为什么第二个工作而不是第一个工作?我以为FractionalNumFractional与兼容Num)的子集

UPD 2:

感谢您的评论,但我仍然感到困惑。工作原理:

f :: Num a => a -> a
f a = a

f 1.0
Run Code Online (Sandbox Code Playgroud)

而这不是:

f :: Num a => a
f = 1.0
Run Code Online (Sandbox Code Playgroud)

UPD 3: 我刚刚注意到以下几点:

f :: Num a => a
f = (1::Int)
Run Code Online (Sandbox Code Playgroud)

也不起作用。

UPD 4

据我所知,我一直在阅读所有答案/评论:

f :: Num a => a 
Run Code Online (Sandbox Code Playgroud)

是Scala的等价于

def f[A: Num]: A
Run Code Online (Sandbox Code Playgroud)

这将解释为什么a调用者定义了许多提到的内容。我们可以这样写的唯一原因:

f :: Num a => a 
f = 1
Run Code Online (Sandbox Code Playgroud)

是因为1键入为Num a => a。有人可以确认这个假设吗?无论如何,谢谢大家的帮助。

chi*_*chi 9

如果我有f :: Num a => a这意味着我可以f在需要任何数字类型的任何地方使用。因此,所有f :: Int,都f :: Double必须键入check。

在您的情况下,1.0 :: Int由于相同的原因我们不能拥有543.24 :: Int,即Int不代表小数。但是,1.0它适合任何小数类型(543.24也是)。

Fractional确实可以认为是的子集Num。但是如果我在所有小数里面都有一个值f :: forall a . Fractional a => a,我不一定在所有的数字类型中都有一个值f :: forall a . Num a => a

请注意,从某种意义上说,约束位于的左侧=>,这使它们的行为相反。即汽车是车辆的一部分,但我不能断定可以在任何汽车中使用的车轮都可以与任何车辆一起使用。相反,相反:可以在任何车辆中使用的车轮将可以在任何汽车中使用。

所以,你可以粗略地认为f :: forall a . Num a => a(值的任何数值类型配件,喜欢35)作为一种亚型 f :: forall a . Fractional a => a(值的任何小数型配件,如3532.43)。

  • @FrancisToth我相信您遇到的问题是,您正在像OOP类一样思考`Num`和`Fractional`。如果是这样的话,那么一个Float实现Fractional接口,也实现Num就可以了。但是Typeclass是关于*参数多态性*的。因此,“ Num a => a”的意思是“这是一个多态值,可以具有属于Num类型类型的任何类型(也有一个实例)。但是5.12不是有效的Int。 Int是Num,因此5.12不是有效的Num a => a,但是5.12属于Num的Fractional子集。 (3认同)
  • 浮点型实现`Num`,但是`1.0 :: Fractional a => a`对于所有实现`Num`的类型都是无效的。 (2认同)
  • @FrancisToth`f :: Num a => a`意味着`f`可以用作* any *数字类型的值,而不是它具有碰巧是数字的单个特定类型。 (2认同)