这是一份关于从 GHC 8.10 升级到 GHC 9.6 的经验报告,主要内容如下:
- 升级背景:在工作中(Groq)将 GHC 版本从 8.10 升级到 9.6,并更新了依赖的 Haskell 包,其中一些变化是“破坏性的”,需要修改自身代码。
- 两种行为:区分了应对包含破坏性变化的升级所需的两种保持行为的更改——“向前兼容的缓解措施”和“破坏性修复”。前者可在升级前进行,后者仅在升级后有效。
- 将破坏性修复转换为向前兼容的缓解措施:可以通过使用 CPP 或“兼容性垫片”将破坏性修复转换为向前兼容的缓解措施。
具体变化:
库的变化:
Prelude
的新导出:新版本base
重新导出liftA2
,导致Control.Applicative
的显式导入发出警告,可选择关闭警告或删除显式导入。ST
的MonadFail
实例删除:在最近的base
版本中删除,可在ST
中使用error
替代fail
。mtl
模块的导出删除:一些mtl
模块删除了与转换器相关的功能的导出,需要从其他地方导入,如Control.Monad.Trans
。aeson
API 变化:版本 2 将 JSON 对象的表示从HashMap Text Value
更改为KeyMap Value
,需要使用新 API 并进行必要的转换。部分修复可通过巧妙使用导入和本地定义作为兼容性垫片实现向前兼容。I64#
变化:Int64
的定义从data Int64 = I64# Int#
更改为data Int64 = I64# Int64#
,需要进行破坏性修复或删除使用该低级表示的代码(幸运的是是向前兼容的缓解措施)。xls
API 变化:xls
库引入RowIndex
和ColumnIndex
抽象类型,需要进行破坏性修复,并可通过定义类型同义词作为兼容性垫片部分实现向前兼容,同时还添加了wsState
字段,需要在构造该类型的值时进行破坏性修复。flatparse
API 变化:许多flatparse
的 API 发生变化,如anyCharASCII
变为anyAsciiChar
,可使用兼容性模块或进行破坏性修复。constraints-extras
的Has
变化:从类型同义词变为类型类,需要进行破坏性修复。genSingletons
:升级后无法使用genSingletons
,需手动编写原本由 Template Haskell 生成的代码。
GHC 的变化:
- 简化的包含:GHC 9.0 切换到更高秩多态性的类型推断方案,导致一些表达式在 GHC 9 系列中无法通过类型检查,可通过手动 eta 展开或禁用简化的包含来缓解。
- GHC 错误:遇到 GHC 在与存在类型相关的代码中出错的问题,通过将内部绑定提升到顶级并标记为
NOINLINE
来缓解。 - 重叠模式:GHC 的模式匹配检查器的改进导致一些模式被检测为冗余,可选择使用
-Wwarn=overlapping-patterns
或删除冗余模式。 - 类型
*
变为Type
:GHC 9 系列在-Wall
中引入关于使用*
作为类型种类的警告,可将*
替换为Data.Kind.Type
。 - GADT 单本地绑定:GHC 9 系列在
-Wall
中引入关于在没有MonoLocalBinds
的情况下对 GADT 进行模式匹配的警告,可启用MonoLocalBinds
或禁用gadt-mono-local-binds
警告。
工具的变化:
brittany
不再维护:不再使用brittany
格式化部分代码。- Hadrian:在启用交叉编译时,Hadrian 拒绝构建
ghci
,不再构建交叉编译的 GHC。
- 经验总结:希望这份报告能衡量跟上 Haskell 生态系统中破坏性变化所需的努力,鼓励库和编译器维护者在合理的情况下避免进行破坏性更改,并在进行破坏性更改时以允许向前兼容缓解而不是破坏性修复的方式进行。同时提到了The Opaleye API breakage policy通过大量使用兼容性垫片来维护。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。