我一直在玩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
,有些则不是。例如,Int
是Integral
类型,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
也可以采用一个复数,然后它将返回一个复数。带有
g
和h
这样的签名的键是它们可以在多种类型上使用,只要返回类型与输入类型相同即可。