Haskell中为何要对()类型的值进行检查?
为什么Haskell中对
()类型的bottom值操作会触发异常? 在Haskell中,()类型仅有两个“值”:()本身,以及bottom(代表未定义、异常或非终止的情况)。从逻辑上看,检查类型为()的表达式e毫无意义——要么e就是(),要么检查动作会导致原本不会崩溃的程序触发异常。
我曾认为针对()类型值的操作不会检查具体值,也不会区分()和bottom,但实际测试结果却并非如此:
▎λ ghci GHCi, version 9.0.2: https://www.haskell.org/ghc/ :? for help ghci> u = (undefined :: ()) ghci> show u "*** Exception: Prelude.undefined CallStack (from HasCallStack): error, called at libraries/base/GHC/Err.hs:75:14 in base:GHC.Err undefined, called at <interactive>:1:6 in interactive:Ghci1 ghci> () == u "*** Exception: Prelude.undefined CallStack (from HasCallStack): error, called at libraries/base/GHC/Err.hs:75:14 in base:GHC.Err undefined, called at <interactive>:1:6 in interactive:Ghci1 ghci> f () = "ok" ghci> f u "*** Exception: Prelude.undefined CallStack (from HasCallStack): error, called at libraries/base/GHC/Err.hs:75:14 in base:GHC.Err undefined, called at <interactive>:1:6 in interactive:Ghci1
可能的原因解释
针对这个现象,主要有几种合理的解释:
- 语义一致性约束:Haskell的语义明确规定,解构任意代数数据类型(ADT)时必须检查值的构造子。哪怕是
()这种最简单的ADT,case (undefined :: ()) of { () -> ... }如果不抛出异常,就会违反语言的基础语义规则。 - 成本收益不对等:
()类型确实是极端特殊的情况,但要为它单独修改语言规范或编译器逻辑,会增加语言的复杂度,而能带来的实际收益却极低——这类场景几乎不会影响常规业务代码的运行。 - 语义一致性+成本考量的结合:Haskell完全可以专门规定,当
case表达式的目标是()类型时跳过检查,但这样做会让语言规范变得冗余,投入的精力远大于能获得的价值。 - bottom传播的必要性:在部分场景下,我们需要让bottom(异常/未定义状态)正确传播,以此暴露程序中的错误,而非静默忽略。对
()类型的操作保留检查,能保证这种错误传播行为的一致性。
内容的提问来源于stack exchange,提问作者Quelklef
相关产品推荐
相关产品推荐

