我一直在玩Haskell中的基本函数,并且对函数f的以下类型声明之间的区别有点困惑

f :: Integer -> Integer

相对
f :: Integral n => n -> n

到目前为止,我已经将两者视为完全相同,但是我确定这是不正确的。有什么区别?

编辑:作为对第一个答案的答复,我想提出一个类似的示例,更多的是根据我所持问题的思路进行的。

考虑以下声明
f :: Num n => n -> n

或者
f :: Num -> Num

每种功能提供什么?

最佳答案

让我们重命名:

f :: Integer -> Integer
g :: (Integral n) => n -> n

我喜欢遵循一种相当普遍的做法,即在签名的约束部分添加括号。它可以帮助它脱颖而出。
f :: Integer -> Integer很简单,它需要一个整数并返回另一个整数。

至于g :: (Integral n) => n -> n:Integral本身不是类型,而是更像谓词。有些类型是Integral,有些则不是。例如,IntIntegral类型,Double不是。

这里n是一个类型变量,它可以引用任何类型。 (Integral n)是对类型变量的约束,它限制了它可以引用的类型。因此,您可以这样阅读:



如果我们检查Integral类型类:
ghci> :info Integral
class (Real a, Enum a) => Integral a where
  quot :: a -> a -> a
  rem :: a -> a -> a
  div :: a -> a -> a
  mod :: a -> a -> a
  quotRem :: a -> a -> (a, a)
  divMod :: a -> a -> (a, a)
  toInteger :: a -> Integer
 {-# MINIMAL quotRem, toInteger #-}
    -- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’

我们可以看到3种内置类型,即Integral。这意味着g同时具有三种不同的类型,具体取决于使用方式。
g :: Word -> Word
g :: Integer -> Integer
g :: Int -> Int

(而且,如果您将来定义了另一种Integral类型,那么g也将自动使用该类型)
Word -> Word变体就是一个很好的例子,因为Word不能为负数。 g当给定正数的机器大小数时,返回另一个正数的机器大小数,而f可以返回任何整数,包括负数或硕大的整数。
Integral是一个相当具体的类。使用Num可以更容易地看到它,它具有较少的方法,因此可以表示更多的类型:
h :: (Num a) => a -> a

这也是f的概括,也就是说,您可以在需要使用h类型的内容的地方使用f。但是h也可以采用一个复数,然后它将返回一个复数。

带有gh这样的签名的键是它们可以在多种类型上使用,只要返回类型与输入类型相同即可。

09-25 18:03
查看更多