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,因为 stringString。在尝试使用时,它会继续爆炸。

RankNTypes 允许你改为按如下方式编写类型签名,对所有满足 show'类型的函数进行量化:

foo :: (forall a. Show a => (a -> String)) -> String -> Int -> IO ()

这是 2 级多态:我们断言 show'函数必须适用我们函数中的所有 as,并且之前的实现现在可以工作。

RankNTypes 扩展允许在类型签名中任意嵌套 forall ... 块。换句话说,它允许秩 N 多态性。