"标记"标准方式是什么?模式匹配表达式中无法访问的案例?例如,对于Aeson,我有Value并需要解压缩它。我使用模式匹配来做,我知道它的对象,它不是数组,字符串,数字等,因为我创建了它。所以,我会有_ -> something
这样的案例。什么必须是something
?我的意思是标准的Haskell,而不是LiquidHaskell方法:)它是error "Internal error"
还是其他东西?
答案 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的多毛二分为各种类型 - 构造函数都来自相同的原始类型。