10

Consider the following data type and pattern synonyms:

{-# LANGUAGE PatternSynonyms, NamedFieldPuns #-}

data Foo = Foo {
      a :: Int
    , b :: String
    , c :: Maybe Bool
}

pattern Bar a b <- Foo { a, b }
pattern Baz c <- Foo { c }

I'd like to match a Foo but get all of a, b, and c. Something like this (invalid Haskell):

showit :: Foo -> String
showit (Bar a b & Baz c) = show a ++ b ++ show c

One option is to use a ViewPattern:

dup :: a -> (a, a)
dup a = (a, a)

showall' :: Foo -> String
showall' (dup -> (Bar a b, Baz c)) = show a ++ b ++ show c

But this results in a non-exhaustive match warning. But we know that Bar and Baz are irrefutable so matching each is also irrefutable.

How can this be expressed without a compiler warning?

The motivation for this is to have fine-grained pattern synonyms against fields of a large data type and allow callers to extract just the desired fields similar to records with NamedFieldPuns. Pattern synonyms don't yet support record syntax, but it's in the works : https://ghc.haskell.org/trac/ghc/ticket/8582

In my case I cannot expose the constructor from the module since I'm using the "smart-constructor" pattern, and hence cannot give callers the benefit of record pattern matching with NamedFieldPuns.

See https://stackoverflow.com/a/25161749/3198498 as the inspiration. I'm trying to expand the idea in that answer to allow callers to arbitrarily extract n of m fields, for a largish m.

Edit: It turns out there is a rather broad problem with PatternSynonyms and exhaustiveness checks : https://ghc.haskell.org/trac/ghc/ticket/10339 This seems to make pattern synonyms used as field extractors very unpleasant when compiling with warnings enabled.

Community
  • 1
  • 1
wrl
  • 131
  • 4
  • This is probably not what you want, but what about: `pattern Barz a b c <- Foo { a b c }`? – Alexis Dumas Sep 01 '15 at 23:16
  • @ChristopherDumas - I'm hoping to find a solution with either a single pattern per field, or a pattern with a record-like syntax using names since Foo may have 10 or more fields. The good news is that ticket 8582 is slated for inclusion in the next version of GHC, so we should get pattern synonyms with record syntax then. – wrl Sep 08 '15 at 03:19

1 Answers1

1

Not sure if this is at all helpful, but I will give it a shot. Would either of these solutions be acceptable?

showit :: Foo -> String
showit x@(Bar a b) = show a ++ b ++ show (c x)

showit' :: Foo -> String
showit' x@(Bar a b) = show a ++ b ++ showthat x
  where
    showthat (Baz c) = show c
archaephyrryx
  • 415
  • 2
  • 10