Reputation: 113
So, I create a data type
data Expr a = Const a
| Expr a :*: Expr a
And I define an instance for Eq
for this data type
instance (Eq m) => Eq (Expr m) where
Const a == Const b = a == b
(a :*: b) == (c :*: d) = ((a == c) && (b == d)) || ((a == d) && (b == c))
This definition means that order does not matter when comparing two expressions. However, when I use pattern matching to write a function that takes Expr
s I cannot just write
f (Const 1 :*: a) = ...
but must also write
f (a :*: Const 1) = ...
in order to catch all cases, even though if I where to compare the two using (==)
it would return true.
Is there a way to write just one of the above to expressions and let the instance of Eq
take care of the rest? Does pattern matching even use or require an instance of Eq
?
Upvotes: 1
Views: 204
Reputation: 170745
Is there a way to write just one of the above to expressions and let the instance of (Eq) take care of the rest?
No.
Does pattern matching even use or require an instance of (Eq)
Only when matching against (number, character or string) literals. You can see the rules in 3.17.2 of https://www.haskell.org/onlinereport/exps.html#pattern-matching and note that case 7 is the only one which mentions ==
.
But you can use view patterns:
const1 (Const 1 :*: a) = Just a
const1 (a :*: Const 1) = Just a
const1 _ = Nothing
f (const1 -> Just a) = ...
This may be too ugly if you need other symmetries in other cases and I can't think of a solution for this at the moment.
Upvotes: 3
Reputation: 120711
An Eq
instance has no bearing whatsoever on pattern matches. ==
is just a library function and checks a particular property that doesn't necessarily have much to do with implementation structure, whereas pattern matches are all about deconstructing a type in its actual ADT structure.
That said, it is possible to fake something similar to what you asked, but I daresay it's not a very good idea to actually do this – doesn't scale and might lead to strange issues later on.
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
matchConstFactor :: Expr a -> Maybe (a, Expr a)
matchConstFactor (Const a :*: b) = Just (a, b)
matchConstFactor (a :*: Const b) = Just (b, a)
matchConstFact _ = Nothing
pattern (:.*:) :: a -> Expr a -> Expr a
pattern a :.*: b <- (matchConstFactor -> Just (a, b))
where a :.*: b = Const a :*: b
Upvotes: 3