monad 定义中的 forall 只是为了使全称量化更加明确。如果你有一个没有进一步限制的类型变量,它默认是通用的,即可以是任何东西。
因此,让我们看看 forall 的两种用法之间的区别以及 haskell 如何看待它们:
隐式:
foo :: (x -> f x) -> a -> b -> (f a, f b)
-- same as
foo :: forall f x a b . (x -> f x) -> a -> b -> (f a, f b)
-- our function is applied to a, so x is equal to a
foo :: forall f x a b . (x ~ a) => (x -> f x) -> a -> b -> (f a, f b)
-- our function is also applied to b, so x is equal to b
foo :: forall f x a b . (x ~ a, x ~ b) => (x -> f x) -> a -> b -> (f a, f b)
哦,(x ~ a, x~ b) 需要 (a ~ b)。这将在没有注释的情况下推断出来,但是由于我们明确使用了不同的类型变量,所以一切都爆炸了。为了解决这个问题,我们需要 f 在我们的函数中保持多态性。
标准的 haskell 无法表达这一点,所以我们需要 rank2types 或 rankntypes。有了它,我们可以写:
foo :: (forall x . x -> f x) -> a -> b -> (f a, f b)
请注意,forall 是函数类型的一部分。这样,它在我们的函数中保持多态,我们可以将它应用于不同的类型,而不会发生任何事情!
请注意,我们也可以这样做:
foo :: Monad m => a -> b -> (m a, m b)
foo a b = (return a, return b)