首页 > 解决方案 > Haskell 中函数类型的差异

问题描述

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

f :: Integer -> Integer

相对

f :: Integral n => n -> n

到目前为止,我将这两者视为相同,但我确信这不是真的。有什么区别?

编辑:作为对第一个答案的回应,我想提出一个类似的例子,它更符合我持有的问题。

考虑以下声明

f :: Num n => n -> n

或者

f :: Num -> Num

每个提供什么功能?

标签: functionhaskell

解决方案


让我们重命名:

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

我喜欢遵循一种相当普遍的做法,即在签名的约束部分添加括号。它有助于它脱颖而出。

f :: Integer -> Integer很简单,它接受一个整数并返回另一个整数。

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

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

g接受任何类型 n的值并返回相同类型的值,前提是它是一个Integral类型。

如果我们检查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例子,因为Words 不能是负数。 g,当给定一个机器大小的正数时,返回另一个机器大小的正数,而f可以返回任何整数,包括负数或大数。

Integral是一个比较具体的类。使用 更容易看出Num,它的方法更少,因此可以表示更多类型:

h :: (Num a) => a -> a

这也是 的概括f,也就是说,您可以在预期具有 ' 类型的h东西的地方使用。fh也可以取一个复数,然后它会返回一个复数。

g像's 和's 这样的签名的关键h是它们适用于多种类型,只要返回类型与输入类型相同。


推荐阅读