haskell - haskell 如何确定隐式 foralls 中类型变量的顺序?
问题描述
所以我最近才了解并开始使用TypeApplications
,并且想知道我们通常如何知道我们正在分配的类型变量。我发现的文档TypeApplications
提到:
使用什么顺序来实例化类型变量?
出现在 foralls 中的类型变量的从左到右的顺序。这是在类型变量级别完成实例化时发生的最合乎逻辑的顺序。嵌套 forall 的工作方式略有不同,但在具有多个变量的单个 forall 位置,会发生从左到右的顺序。(请参阅下面的嵌套 foralls)。
但是,我还没有提到隐式 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)
再说一次,这可能只是 8.0.2 中如何打印 foralls 的一个错误,因为否则类型应用程序似乎是使用 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)
看,没有{…}
类型变量!
这个订单是从哪里来的?
如果标识符的类型签名不包括显式的 forall,则类型变量参数按照变量在类型中出现的从左到右的顺序出现。因此, foo :: Monad m => ab -> m (ac) 的类型变量将按 m、a、b、c 排序。
这仅适用于具有显式类型签名的事物。推断类型中的变量没有保证顺序,但您也不能使用带有推断类型的表达式VisibleTypeApplication
。
推荐阅读
- reactjs - 构建 JS 包时的 Expo 启动错误:在 HMRClient.js 中进行类型转换
- sql-server - 如何合并2个相同数据库之间的所有表数据
- outlook - 任何人都可以理解或阅读 Microsoft 反垃圾邮件标头吗?
- ios - 线程 1:EXC_BAD_ACCESS(代码=1,地址=0x2d006e0080)
- ios - 核心图像颜色的 Colorwithpattern
- python - 回归神经网络返回低范围值进行预测
- wordpress - 网站已从恶意软件中清除,但仍会生成随机 url
- c# - 在流(Rx)产生的第一个值上终止循环
- c# - 语言特殊字符标准化为 ansi
- python - 使用从循环内的代码片段中提取的函数避免代码冗余/计算开销