Haskell中的Or模式

时间:2014-07-11 14:59:43

标签: haskell ocaml

在OCaml中,我习惯于编写代码如下:

let combine o1 o2 = match o1, o2 with
    | Valid, Invalid | Invalid, Valid -> Invalid
    | _ -> ...

我没有找到在Haskell中编写 or-patterns 的方法,我真的很想念它。有没有人有解决方案?

3 个答案:

答案 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)

如果您想匹配不同类型的值(例如IntBool),您可以创建一些受约束的存在类型

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