因此,我最近才了解并开始使用TypeApplications
,并且想知道我们通常如何知道要分配的类型变量。我找到的文档中TypeApplications
提到:
使用什么顺序来实例化类型变量?
类型变量从左到右的顺序出现在forall中。这是在类型变量级别进行实例化时发生的最合乎逻辑的顺序。嵌套的forall的工作方式略有不同,但是在具有多个变量的单个forall位置,发生了从左到右的顺序。(有关嵌套的forall,请参见下文)。
但是我还没有提到如何确定隐式forall中类型变量的顺序。我尝试查看不同的示例-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)
再说一遍,也许这仅仅是在8.0.2中打印allall的方式中的一个错误,因为否则类型应用程序似乎是使用forall的变量从右到左完成的,这与文档中所说的相反:
> :t (,,) @Bool
(,,) @Bool :: forall {c} {b}. Bool -> b -> c -> (Bool, b, c)
那么,将类型变量放入隐式forall中的顺序是否总是按照它们在类型主体中从左到右的顺序出现(包括约束)?
TL; DR:类型变量顺序由第一次从左到右的相遇确定。如有疑问,请使用:type +v
。
:type
:type
在这里使用会产生误导。:type
推断整个表达式的类型。因此,当您编写时:t (,)
,类型检查器会查看
(,) :: forall a b. a -> b -> (a, b)
并使用新鲜的类型变量实例化所有的
(,) :: a1 -> b1 -> (a1, b1)
如果您要申请的话,这是必要的(,)
。las,您没有,所以类型推断几乎完成了,并且将所有自由变量都推广了,例如,
(,) :: forall {b} {a}. a -> b -> (a, b)
此步骤不能保证free变量的顺序,并且编译器可以自由更改。
还要注意,它写的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)
看,没有{…}
类型变量!
如果标识符的类型签名不包括显式的forall,则类型变量参数以从左到右的顺序出现,其中变量在类型中出现。因此,foo :: Monad m => ab-> m(ac)将其类型变量按m,a,b,c进行排序。
这仅适用于具有显式类型签名的事物。推断类型中的变量没有确定的顺序,但是您也不能将推断类型中的表达式与一起使用VisibleTypeApplication
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句