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://mcmap.net/q/440701/-is-it-possible-to-export-constructors-for-pattern-matching-but-not-for-construction-in-haskell-modules 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.
pattern Barz a b c <- Foo { a b c }
? – Brownnose