Haskell PVP为何判定新增导出函数为非破坏性变更?
Haskell PVP判定新增导出为非破坏性变更的原因解析
代码背景
本地代码
module A where x :: Int x = 5 module Main where import A import Lib main :: IO () main = print (x + y)
外部库Lib初始版本(v0.1.0.0)
module Lib where y :: Int y = 10
外部库Lib更新版本(v0.1.1.0)
module Lib where x :: Int x = -- 任意Int值 y :: Int y = 10
PVP的判定逻辑
Haskell的包版本政策(PVP)对版本变更的规则定义如下:
- 主版本号(第一个数字)变更:对应破坏性变更,比如修改/移除原有导出项、类型签名等
- 次版本号(第二个数字)变更:对应非破坏性的新增操作,比如添加新的导出项、函数、类型
- 补丁版本(第三、四位):仅用于bug修复,不改动对外API
当Lib从v0.1.0.0升级到v0.1.1.0时,仅新增了x到导出列表,没有修改或删除原有导出的y,完全符合PVP中“次版本号对应非破坏性新增”的规则,因此被判定为非破坏性变更。
原有代码编译失败的原因
原有Main模块使用了无限定导入(import Lib),会导入Lib的所有导出符号。当Lib新增导出x后,Main中的x同时来自A和Lib,触发名称歧义错误。
为什么PVP的断言依然成立
PVP的“非破坏性”是针对遵循规范的库使用方式而言的:
- 如果用户代码使用显式导入(比如
import Lib (y)),只导入需要的符号,就不会出现歧义 - 如果用户使用限定导入(
import qualified Lib as L),通过限定符访问符号,也不会产生冲突
无限定导入所有符号本身是一种脆弱的写法,依赖于库的导出列表不会新增同名符号,这种写法不在PVP承诺兼容的范围内。PVP的设计目标是保证正确使用API的代码可以平滑升级,而非覆盖所有可能的使用场景。
内容的提问来源于stack exchange,提问作者Janus Troelsen
相关产品推荐
相关产品推荐

