haskell - GHC/GHCi 意外接受的代码
问题描述
我不明白为什么这段代码应该通过类型检查:
foo :: (Maybe a, Maybe b)
foo = let x = Nothing in (x,x)
由于每个组件都绑定到同一个变量x
,我希望这个表达式的最通用类型是(Maybe a, Maybe a)
。如果我使用 awhere
而不是 a ,我会得到相同的结果let
。我错过了什么吗?
解决方案
简而言之, 的类型x
被 泛化let
。这是Hindley-Milner类型推理算法中的关键步骤。
具体来说,let x = Nothing
最初分配x
type Maybe t
,其中t
是一个新的类型变量。然后,类型被泛化,普遍量化它的所有类型变量(技术上:除了在其他地方使用的那些,但这里我们只有t
)。这导致x :: forall t. Maybe t
. 请注意,这与Nothing :: forall t. Maybe t
.
因此,每次我们x
在代码中使用时,都指代一种可能不同的类型Maybe t
,就像Nothing
. 由于这个原因,使用(x, x)
得到相同的类型。(Nothing, Nothing)
相反,lambda不具有相同的泛化步骤。相比之下, (\x -> (x, x)) Nothing
“only”具有 type forall t. (Maybe t, Maybe t)
,其中两个组件都被强制为同一类型。这里x
再次分配了 type Maybe t
,带有t
fresh,但不是泛化的。然后(x, x)
被分配 type (Maybe t, Maybe t)
。仅在顶层我们推广了加法forall t
,但此时获得异构对为时已晚。
推荐阅读
- python - FailedPreconditionError(参见上面的回溯):GetNext() 失败,因为迭代器尚未初始化
- android - TextView SetText 不刷新 UI Android 上的文本
- android - (Android) 从 BLE 设备的自定义特征中获取数据的问题
- mysql - 我如何计算表中的项目数并与mysql数据库中不同表中的类别连接
- c++ - 如何在 C++ 中输入鼠标按钮
- typescript - Typescript 泛型类型不强制类型安全
- android - 在 kotlin 中实现状态持久化
- ios - 运行目标 My Mac 对运行方案“My-iOS-App”无效
- laravel - Laravel Passport 令牌到期
- java - 使用 createNativeQuery 时如何在 INSERT 语句中查找 SQLGrammarException