非多态函数的多态签名:为什么不呢?

cro*_*eea 6 polymorphism haskell

举个例子,考虑一下琐碎的功能

f :: (Integral b) => a -> b
f x = 3 :: Int
Run Code Online (Sandbox Code Playgroud)

GHC抱怨它不能推断(b~Int).该定义匹配签名,因为它返回的是Integral(即Int).为什么GHC会强迫我使用更具体的类型签名?

谢谢

ham*_*mar 17

Haskell中的类型变量是普遍量化的,因此Integral b => b不仅仅意味着某种 Integral类型,它意味着任何 Integral类型.换句话说,调用者可以选择应该使用哪种具体类型.因此,Int当类型签名说我应该能够选择任何Integral类型时,函数总是返回一个类型错误,例如IntegerWord64.

有一些扩展允许您使用存在量化的类型变量,但它们使用起来比较麻烦,因为它们需要包装类型(为了存储类型类字典).大多数时候,最好避免它们.但是如果你确实想要使用存在类型,它看起来像这样:

{-# LANGUAGE ExistentialQuantification #-}

data SomeIntegral = forall a. Integral a => SomeIntegral a

f :: a -> SomeIntegral
f x = SomeIntegral (3 :: Int)
Run Code Online (Sandbox Code Playgroud)

然后,使用此函数的代码必须具有足够的多态性以适用于任何Integral类型.我们还必须使用模式匹配case而不是let保持GHC的大脑不受爆炸.

> case f True of SomeIntegral x -> toInteger x
3
> :t toInteger
toInteger :: Integral a => a -> Integer
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,您可以将其x视为具有类型exists b. Integral b => b,即某种未知Integral类型.