鉴于以下代码(来自Yoneda Lemma explanation):
{-# LANGUAGE RankNTypes #-}
check1 :: a -> (forall b . (a -> b) -> b)
check1 a f = f a
uncheck1 :: (forall b . (a -> b) -> b) -> a
uncheck1 t = t id
在forall
中确认check1
rank-1
的{{1}}量化似乎是ghci
:
$ :t check1
check1 :: a -> (a -> b) -> b
$ :t uncheck1
uncheck1 :: (forall b. (a -> b) -> b) -> a
我无法弄清楚为什么check1
具有rank-1
类型签名,而uncheck1
仍保留rank-2
类型签名。我将check1
的类型签名读作"对于所有类型b
,请接受a
类型的函数到b
,其中a
是固定的,并返回类型b
"的值。这使我相信不允许用户提前选择类型b
(与类型a
不同),因此类型应为rank-2
。在尝试了解明确的forall
签名是否应该被读为1级或更高级别时,我肯定会发现一些细微差别。
更新
虽然我已经接受了下面的答案,但capital lambda
来自Lennart Augustsson的this email explanation在forall
方面非常明确和直观 - 它切断了来电者的混淆,并清楚地显示了如何进行打字 - 级别lambda来解释{{1}}。
答案 0 :(得分:5)
碰巧我们可以漂浮在forall
check1
,因为它位于该箭头的右侧。
check1 :: a -> (forall b. (a -> b) -> b)
check1 :: forall b. a -> (a -> b) -> b
对uncheck1
的直觉,谁能选择b
是什么?某些不是来电者,因为该功能必须适用于所有b
。
在check1
中,调用者确实可以选择b
,因为我们必须返回一个适用于所有b
的函数。我们将功能返回给他们,因此他们可以将它专门用于他们选择的任何内容。由于调用者无论如何都可以选择,这与
check1 :: a -> (a -> b) -> b
HaskellWiki页面对此进行了讨论。