见6.4.14.1. Inferred vs. specified type variables:
从 9.0.1 版本开始,GHC 允许将用户编写的类型或种类变量标记为 inferred,这与默认的 specified 不同。通过将大括号中的类型变量绑定器写入{tyvar} 或{tyvar :: kind},新变量将被分类为推断,而不是指定。
forall a. 和 forall {a}. 是 GHC 将通过统一自动实例化的不可见量词。
const :: forall a b. a -> b -> a
const a _ = a
这意味着 const True EQ 在没有用户帮助的情况下实例化 a (@Bool) 和 b (@Ordering)。
如果用户想要显式实例化它们,他们可以使用可见类型应用程序“覆盖其可见性”。这就是为什么它们是指定类型。 (尽管“特定able”可能是更准确的术语)
>> :set -XTypeApplications
>> :t const @Bool @Ordering True EQ
const @Bool @Ordering True EQ :: Bool
如果出于某种原因我们只想指定 b(不召唤“蜗牛小队”:@_, umm "partial type signatures")我们可以制作 a 推断类型。然后第一种类型被丢弃
const2 :: forall {a} b. a -> b -> a
const2 a _ = a
>> :t const2 @Ordering True EQ
const2 @Ordering True EQ :: Bool
对于您的示例,这意味着 ghc 必须推断 f 和 p 的类型。你不能写ign @IO @Int。
当你有善良的多态性时,这会变得更有用。如果你定义
-- MkApply @Type @[] @Int :: [Int] -> Apply @Type [] Int
-- MkApply @_ @[] @Int :: [Int] -> Apply @Type [] Int
type Apply :: forall (k :: Type). (k -> Type) -> (k -> Type)
newtype Apply f a where
MkApply :: forall (k :: Type) (f :: k -> Type) (a :: k). f a -> Apply @k f a
在实例化MkApply @Type @[] @Int 时必须指定类型k,但[] 和Int 都隐含了这种类型。您可能更喜欢将 k 标记为 MkApply 中的推断,以便您可以编写 MkApply @[] @Int
-- MkApply @[] @Int :: [Int] -> Apply @Type [] Int
type Apply :: forall (k :: Type). (k -> Type) -> (k -> Type)
newtype Apply f a where
MkApply :: forall {k :: Type} (f :: k -> Type) (a :: k). f a -> Apply @k f a