How to make PatternSynonym matching multiple data constructors?

Hi,

I would like to define a pattern synonym for a sum type to extract 1 field from both data constructors.
Looks like doable but GHC cannot compile following snippet:

data FooBar = Foo Int String | Bar String
pattern FooBarStr :: String → Foo
pattern FooBarStr s ← Foo _ s
pattern FooBarStr s ← Bar s

Originally Foo type was defined as:

data Foo = Foo (Maybe Int) String

But I have a problem with using a generated prism

( _Foo # Nothing ) – is not the same as _Bar of FooBar

You can do it with ViewPatterns:

{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}

data FooBar = Foo Int String | Bar String

fooBarStr (Foo _ x) = x
fooBarStr (Bar x) = x

pattern FooBarStr :: String -> FooBar
pattern FooBarStr s <- (fooBarStr -> s)

I don’t think there is another way.

2 Likes

Hi Daneel, you’re not alone in wanting more flexibility with pattern decls and constructors. The syntax would perhaps look more like:

pattern FooBarStr s <- Foo _ s
        FooBarStr s <- Bar s
  where ...

The compiler would need to see all the <- equations together, so it can desugar that to a single case statement.

Sadly, as @jaror says, the only way to achieve it today is with ViewPatterns – which I find particularly non-intuitive with that arrow from an invisible argument.

1 Like