在OCaml中,我习惯于编写代码如下:
let combine o1 o2 = match o1, o2 with
| Valid, Invalid | Invalid, Valid -> Invalid
| _ -> ...
我没有找到在Haskell中编写 or-patterns 的方法,我真的很想念它。有没有人有解决方案?
答案 0 :(得分:19)
我不认为这在haskell中是可行的。但是,有一些选择:
where
绑定这在您的示例中没有多大意义,但如果您在case表达式的主体中有更多代码,那么它很有用:
combine o1 o2 = case (o1,o2) of
(Valid, Invalid) -> handleInvalid
(Invalid, Valid) -> handleInvalid
...
where
handleInvalid = ...
根据我的经验,您不希望在一个模式匹配中使用两个或模式。在这种情况下,您可以处理所有“好”的情况,并使用外卡模式:
combine o1 o2 = case (o1,o2) of
(Valid, Valid) -> Valid -- This is the only valid case
_ -> Invalid -- All other cases are invalid
这样做的缺点是它绕过了穷举检查器,并且你不能将通配符模式用于其他目的。
==
如果要匹配的类型是类似枚举的类型,您可以考虑创建Eq
实例。然后,您可以使用==
和||
来匹配一个警卫中的多个构造函数:
combine o1 o2
| o1 == Invalid && o2 == Valid || o1 == Valid && o2 == Invalid = Invalid
| ...
我同意这看起来不太好,它也有绕过穷举检查器的缺点,并且如果模式重叠则不会警告你,所以我不推荐它。
答案 1 :(得分:7)
你可以使用这个quasiquoter http://hackage.haskell.org/package/OrPatterns。您的示例转换为:
let combine o1 o2 = case (o1, o2) of
[o| (Valid, Invalid) | (Invalid, Valid ) |] -> Invalid
_ -> ...
答案 2 :(得分:1)
向GHC添加or-patterns有proposal。
在那之前(除了其他例子),pattern synonyms可用于类似的方式:
data ABC = A Int | B Int | C Bool
ab :: ABC -> Maybe Int
ab (A i) = Just i
ab (B i) = Just i
ab C{} = Nothing
pattern AB :: Int -> ABC
pattern AB i <- (ab -> Just i)
如果您想匹配不同类型的值(例如Int
和Bool
),您可以创建一些受约束的存在类型
data Showable where
Showable :: Show a => a -> Showable
ac :: ABC -> Maybe Showable
ac (A i) = Just (Showable i)
ac (C b) = Just (Showable b)
ac B{} = Nothing
pattern AC :: () => Show a => a -> ABC
pattern AC showable <- (ac -> Just (Showable showable))
showAC :: ABC -> String
showAC (AC showable) = "A or C: " ++ show showable
showAC (B i) = "B: " ++ show i