[Haskell-cafe] Disjunctive patterns

Asger Feldthaus asger.feldthaus at gmail.com
Thu Dec 8 11:13:39 CET 2011


Haskell doesn't seem to support disjunctive patterns, and I'm having a
difficult time writing good Haskell code in situations that would otherwise
call for that type of pattern.

Suppose for an example I have this data type:

data T = Foo Int | Bar Int | Baz

In OCaml I can write something like:

(* foo : T -> T -> int *)
fun foo x y = match (x,y) with
  | (Foo a | Bar a, Foo b | Bar b) -> a + b
  | (Baz, Foo a)
  | (Bar a, Baz) -> -a
  | (Baz, Bar a)
  | (Foo a, Baz) -> a
  | _ -> 0

In Haskell I can't find any equivalent to the disjunctive pattern. If
expanded naively, my Haskell version would look like this:

foo :: T -> T -> Int
foo x y = case (x,y) of
  (Foo a, Foo b) -> a + b
  (Foo a, Bar b) -> a + b
  (Bar a, Foo b) -> a + b
  (Bar a, Bar b) -> a + b
  (Baz, Foo a) -> -a
  (Bar a, Baz) -> -a
  (Baz, Bar a) -> a
  (Foo a, Baz) -> a
  _ -> 0

While my example is still managable in size, this quickly goes out of hand
in practice. I've tried using pattern guards but with limited success. For
example:

foo2 :: T -> T -> Int
foo2 x y = case (x,y) of
  (x,y) | Just a <- open x,
          Just b <- open y ->
            a+b
  (Baz, Foo a) -> -a
  (Bar a, Baz) -> -a
  (Baz, Bar a) -> a
  (Foo a, Baz) -> a
  _ -> 0
  where
    open (Foo x) = Just x
    open (Bar x) = Just x
    open Baz = Nothing

I admit it doesn't look that bad in my crafted example, but this approach
doesn't seem to well work for me in practice. In any case, it's still far
more verbose than the disjunctive pattern version.

Nesting the case expressions instead of tuple-matching can reduce some code
duplication, but in general it becomes really verbose, and it is easy to
make mistakes when you have partially overlapped patterns in the
disjunctive-pattern version. Here's the example with nested cases:

foo3 :: T -> T -> Int
foo3 x y = case x of
  Foo a -> case y of
    Foo b -> a+b
    Bar b -> a+b
    Baz -> a
  Bar a -> case y of
    Foo b -> a+b
    Bar b -> a+b
    Baz -> -a
  Baz -> case y of
    Foo b -> -b
    Bar b -> b
    Baz -> 0

What do people do in this situation - is there a good trick I've
overlooked? And is there some reason why Haskell does not support
disjunctive patterns?

Thanks,
Asger
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20111208/9ea36504/attachment.htm>


More information about the Haskell-Cafe mailing list