[Haskell-cafe] Disjunctive patterns

Emil Axelsson emax at chalmers.se
Thu Dec 8 13:15:34 CET 2011


Instead of pattern guards you can use ViewPatterns:

   http://hackage.haskell.org/trac/ghc/wiki/ViewPatterns

This reduces some of the noise.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{-# LANGUAGE ViewPatterns #-}

data T = Foo Int | Bar Int | Baz

fooBar (Foo a) = Just a
fooBar (Bar a) = Just a
fooBar _       = Nothing

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

/ Emil


2011-12-08 11:13, Asger Feldthaus skrev:
> 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
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe



More information about the Haskell-Cafe mailing list