举个例子,考虑一下琐碎的函数
f :: (Integral b) => a -> b
f x = 3 :: Int
GHC抱怨它不能推断(b~Int)。该定义匹配签名,因为它返回的是Integral(即Int)。为什么GHC会强迫我使用更具体的类型签名?
由于
答案 0 :(得分:17)
Haskell中的类型变量是普遍量化的,因此Integral b => b
并不仅仅意味着某些 Integral
类型,它意味着任何 {{1 }类型。换句话说,调用者可以选择应该使用哪种具体类型。因此,当类型签名说我应该能够选择任何Integral
类型时,函数总是返回Int
,这显然是一个类型错误。 Integral
或Integer
。
有一些扩展允许你使用existentially quantified type variables,但它们使用起来比较麻烦,因为它们需要一个包装类型(为了存储类型类字典)。大多数时候,最好避免它们。但如果你确实想使用存在类型,它看起来像这样:
Word64
使用此函数的代码必须具有足够的多态性才能使用任何{-# LANGUAGE ExistentialQuantification #-}
data SomeIntegral = forall a. Integral a => SomeIntegral a
f :: a -> SomeIntegral
f x = SomeIntegral (3 :: Int)
类型。我们还必须使用Integral
而不是case
来模式匹配,以防止GHC的大脑爆炸。
let
在上面的示例中,您可以将> case f True of SomeIntegral x -> toInteger x
3
> :t toInteger
toInteger :: Integral a => a -> Integer
视为具有x
类型,即某种未知exists b. Integral b => b
类型。
答案 1 :(得分:2)
您函数的最常见类型是
f :: a -> Int
使用类型注释,您只能要求您想要更多特定类型,例如
f :: Bool -> Int
但您无法声明 less 特定类型。 Haskell类型系统不允许您进行代码无法保证的承诺。
答案 2 :(得分:0)
正如其他人所说,在Haskell中,如果函数返回类型为x
的结果,则意味着调用者决定实际类型是什么。不是功能本身。换句话说,该函数必须能够返回与签名匹配的任何可能类型。
这与大多数OOP语言不同,这样的签名意味着函数可以选择它返回的内容。显然这让一些人感到困惑......