问题描述
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