Haskell如何确定隐式foralls中类型变量的顺序?



所以我最近才了解并开始使用TypeApplications,并且想知道我们如何通常知道我们分配了什么类型的变量。我找到的关于TypeApplications的文档提到:

使用什么顺序来实例化类型变量?

类型变量出现在forall中的从左到右顺序。这是在类型变量级别完成实例化时发生的最合乎逻辑的顺序。嵌套 forall 的工作方式略有不同,但在具有多个变量的单个 forall 位置,将发生从左到右的顺序。(嵌套的森林见下文(。

但是,我还没有发现提到隐式 foralls 中类型变量的顺序是如何确定的。我尝试用-fprint-explicit-foralls查看不同的示例,看看是否有一个简单的模式,但是在不同版本的ghci中得到了不同的结果。:/

在 ghci 版本 8.0.2 中,我得到:

> :t (,,)
(,,) :: forall {c} {b} {a}. a -> b -> c -> (a, b, c)

而在 ghci 版本 8.4.3 中,我得到:

> :t (,,)
(,,) :: forall {a} {b} {c}. a -> b -> c -> (a, b, c)

再说一次,也许这只是 foralls 在 8.0.2 中打印方式中的一个错误,因为否则类型应用程序似乎使用 forall 的变量从右到左完成,与文档所说的相反:

> :t (,,) @Bool
(,,) @Bool :: forall {c} {b}. Bool -> b -> c -> (Bool, b, c)

那么,类型变量是否总是按照它们在类型主体中从左到右出现的顺序(包括约束(放在隐式 foralls 中?

TL;DR:类型变量顺序由第一次从左到右的遭遇决定。 如有疑问,请使用:type +v.

不要使用:type

在这里使用:type具有误导性。:type推断整个表达式的类型。所以当你写:t (,)时,类型检查器会查看

(,) :: forall a b. a -> b -> (a, b)

并使用新类型变量实例化所有 forall

(,) :: a1 -> b1 -> (a1, b1)

如果您要申请(,),这是必要的。唉,你没有,所以类型推断几乎完成了,它推广到所有自由变量,例如,你得到

(,) :: forall {b} {a}. a -> b -> (a, b)

此步骤不保证自由变量的顺序,并且编译器可以自由更改。

另请注意,它写的是forall {a}而不是forall a,这意味着您不能在此处使用可见类型应用程序。

使用:type +v

但是,当然您可以使用(,) @Bool- 但是在这里,类型检查器以不同的方式处理第一个表达式,并且不执行此实例化/泛化步骤。

你也可以在GHCi中获得这种行为 -+v传递给:type

:type +v (,)
(,) :: forall a b. a -> b -> (a, b)
:type +v (,) @Bool
(,) @Bool :: forall b. Bool -> b -> (Bool, b)

看,没有关于类型变量的{…}

这个订单从何而来?

GHC 用户指南中有关可见类型应用的部分指出:

如果标识符的类型签名不包含显式 forall,则类型变量参数按变量在类型中出现的从左到右顺序显示。所以, foo :: monad m => a b -> m (a c( 将有其类型变量排序为 m, a, b, c。

这仅适用于具有显式类型签名的内容。推断类型中的变量没有保证的顺序,但您也不能将具有推断类型的表达式与VisibleTypeApplication一起使用。

相关内容

  • 没有找到相关文章

最新更新