RankNTypes
想象一下以下情况:
foo::Show a => (a -> String) -> String -> Int -> IO ()
foo show' string int = do
putStrLn (show' string)
putStrLn (show' int)
在这里,我们希望传入一个将值转换为 String 的函数,将该函数应用于字符串参数和 int 参数,并将它们打印出来。在我看来,没有理由这会失败! 我们有一个函数可以处理我们传入的两种类型的参数。
不幸的是,这不会打字检查! GHC 根据函数体中的第一次出现推断出 a
类型。也就是说,只要我们点击:
putStrLn (show' string)
GHC 将推断 show' :: String -> String
,因为 string
是 String
。在尝试使用时,它会继续爆炸。
RankNTypes
允许你改为按如下方式编写类型签名,对所有满足 show'
类型的函数进行量化:
foo :: (forall a. Show a => (a -> String)) -> String -> Int -> IO ()
这是 2 级多态:我们断言 show'
函数必须适用于我们函数中的所有 a
s,并且之前的实现现在可以工作。
RankNTypes
扩展允许在类型签名中任意嵌套 forall ...
块。换句话说,它允许秩 N 多态性。