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.
Consider this usage of your pattern synonym:
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 variablen
must be bound toSucc k
. Given this intuition, we need to find a pattern that does exactly that, a pattern that could be used here instead ofPred n
:It turns out that your view pattern does exactly that. This would work just fine:
Consequently, we have to define
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.