Haskell 中的组匹配模式?

问题描述

我有以下枚举类型的代码,其中包含许多值类型。

data Enum = A1 | A2 | B1 | B2 | B3 | C1 | .. | Z1 | Z2

foo :: Enum -> AnyType
foo A1 = foo1 A1
foo A2 = foo2 A2
foo B1 = foo1 B1
foo B2 = foo2 B2
foo B3 = foo3 B3
foo C1 = foo1 C1
...
foo Z1 = foo1 Z1
foo Z2 = foo2 Z2

这看起来很冗长。如果我将它们分组为 using guard,我不能依靠编译器来帮助检查值类型是否详尽(例如,缺少 Z1),otherwise认值。组也可以包含重复项(例如,[A1,B1,..] 和 [A1,B2])。有没有办法在对模式进行分组的同时让编译器检查缺失和重复的模式?

foo x | x `elem` [A1,C1 {-- ...,Z1,--}] = foo1 x
      | x `elem` [A2,B2] = foo2 x
      | x `elem` [B3] = foo1 x 
      | otherwise = defaultFoo x

解决方法

我建议你让你的数据结构反映你计划计算的编程结构。

data OneOf2 = OneOf2 | TwoOf2
data OneOf3 = OneOf3 | TwoOf3 | ThreeOf3
data Has2 = A | C | ... | Z
data Has3 = B | ...
data Enum = Group2 Has2 OneOf2 | Group3 Has3 OneOf3

您现在可以匹配如下内容:

foo x = case x of
    Group2 _ OneOf2 -> foo1 x
    Group2 _ TwoOf2 -> foo2 x
    Group3 _ OneOf3 -> foo1 x
    Group3 _ TwoOf3 -> foo2 x
    Group3 _ ThreeOf3 -> foo3 x
,

这样的定义在语法上更简单:

bar :: Enum -> Enum -> AnyType
bar x = case x of

  A1 -> foo1
  B1 -> foo1
  C1 -> foo1

  A2 -> foo2
  B2 -> foo2

  B3 -> foo3

那么 foo 可以定义为:

foo :: Enum -> AnyType
foo = join bar