5

With PatternSynonyms (explicitly bidirectional form), the pattern-to-expr equations in effect form a function but spelled upper-case (providing you end up with an fully saturated data constr of the correct type). Then consider (at GHC 8.10.2)

{-# LANGUAGE  PatternSynonyms, ViewPatterns  #-}

data Nat = Zero | Succ Nat                deriving (Eq, Show, Read)

--  Pattern Synonyms as functions?

pattern Pred :: Nat -> Nat
pattern Pred n <- {- what goes here? -}           where
  Pred (Succ n) = n
pattern One           = Succ Zero

zero = Pred One                      -- shows as Zero OK

So what do I put for the pattern Pred n <- ??? value-to-pattern top line? Or can I just not use Pred n in a pattern match? What seems to work (but I don't understand why) is a view pattern

pattern Pred n <-  (Succ -> n)          where ...   -- seems to work, but why?

isZero (Pred One) = True
isZero _          = False

-- isZero (Pred One) ===> True ; isZero Zero ===> True
-- isZero (Succ One) ===> False; isZero One  ===> False

It looks sweet to use Pred as a pseudo-constructor/pattern here, because it's an injective function.

AntC
  • 2,623
  • 1
  • 13
  • 20
  • Related https://stackoverflow.com/questions/37890385/better-way-to-write-a-pattern-synonym, and see the Trac issue link from there. – AntC Mar 02 '21 at 06:11

1 Answers1

6

Consider this usage of your pattern synonym:

succ' :: Nat -> Nat
succ' (Pred n) = n

where the intent is, of course, to return the successor of the argument.

In this case it is clear that when the argument is, say, k, then variable n must be bound to Succ k. Given this intuition, we need to find a pattern that does exactly that, a pattern that could be used here instead of Pred n:

succ' :: Nat -> Nat
succ' ({- bind n to Succ k -}) = n

It turns out that your view pattern does exactly that. This would work just fine:

succ' :: Nat -> Nat
succ' (Succ -> n) = n

Consequently, we have to define

pattern Pred n <- (Succ -> n)

In my own (limited) experience, this is fairly idiomatic. When you have a bidirectional pattern synonym, you will often use a view pattern as done above.

chi
  • 111,837
  • 3
  • 133
  • 218
  • Aha! Would there be a way to do this without View Patterns? (Asking because I find them not intuitive, what with that invisible argument.) – AntC Jan 21 '21 at 01:50
  • @AntC I don't think it's possible without. – chi Jan 21 '21 at 09:06