Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining patterns

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.

like image 799
wrl Avatar asked Aug 10 '15 01:08

wrl


1 Answers

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
like image 154
archaephyrryx Avatar answered Oct 02 '22 01:10

archaephyrryx