如何在模式匹配中标记无法访问的案例

时间:2018-03-27 14:52:20

标签: haskell

"标记"标准方式是什么?模式匹配表达式中无法访问的案例?例如,对于Aeson,我有Value并需要解压缩它。我使用模式匹配来做,我知道它的对象,它不是数组,字符串,数字等,因为我创建了它。所以,我会有_ -> something这样的案例。什么必须是something?我的意思是标准的Haskell,而不是LiquidHaskell方法:)它是error "Internal error"还是其他东西?

1 个答案:

答案 0 :(得分:6)

具有不可能的构造函数在Haskell中是常见的,并且可以根据情况和样式以两种方式之一处理。许多开发人员,特别是那些喜欢Haskell 98代码风格的开发人员,只会通过错误指出不可能的案例:

data SumType1 = ConstrA | ConstrB | ConstrC

anyConstr :: SumType1 -> Int
anyConstr ConstrA = 1
anyConstr ConstrB = 2
anyConstr ConstrC = 3

onlyConstrA :: SumType1 -> Int
onlyConstrA ConstrA = 1
onlyConstrA _ = error "Impossible: internal error, passed wrong constructor."

然而,这并不令人满意,并且要求开发人员在编译器具备能力且更可靠时确保安全性。常见的解决方案是使用只能代表ConstrA的类型。您可以让SumType1为两种类型的总和,其中一种类型的字段为“ConstrAType”,但这种重构可能真的耗尽。有时我更喜欢GADT解决方案:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}

data SumTag = A | Anything
data SumType (a :: SumTag) where
     ConstrA :: SumType A
     ConstrB :: SumType Anything
     ConstrC :: SumType Anything

doAnything :: SumType a -> Int
doAnything ConstrA = 1
doAnything ConstrB = 2
doAnything ConstrC = 3

onlyConstrA :: SumType A -> Int
onlyConstrA ConstrA = 1

现在函数onlyConstrA有一个清楚显示的类型(当与数据声明一起考虑时)它只能应用于ConstrA构造函数。同时我们没有失去任何力量,例如doAnything不需要考虑原始SumType1的多毛二分为各种类型 - 构造函数都来自相同的原始类型。

相关问题