Combining patterns
Asked Answered
E

1

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://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.

Ectype answered 10/8, 2015 at 1:38 Comment(2)
This is probably not what you want, but what about: pattern Barz a b c <- Foo { a b c }?Brownnose
@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.Ectype
W
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
Wane answered 12/8, 2016 at 3:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.