It’s not necessary for this addition operator, but in general you can make a function commutative without implementing all the flipped cases by adding a final equation that flips the arguments:
data X = A | B | C
adjacent A B = True
adjacent B C = True
adjacent A C = False
adjacent x y = adjacent y x -- covers B A, C B, and C A
However, the downside is that if you forget to handle a case, this easily leads to an infinite loop:
adjacent A B = True
adjacent B C = True
adjacent x y = adjacent y x
Here, adjacent A C
would call adjacent C A
, which would call adjacent A C
, and so on. And GHC’s pattern match exhaustivity checking (-fwarn-incomplete-patterns
or -Wall
) won’t help you here.
I guess you could add an additional argument to prevent looping:
data Commute = Forward | Reverse
adjacent = go Forward
where
go _ A B = True
go _ B C = True
go Forward x y = go Reverse y x -- try to commute
go Reverse _ _ = False -- commuting failed
Now GHC will complain if you don’t add the go Reverse
equation to handle the case where you commuted but there was still no match.
But I think this is only suitable for functions with a large number of cases—otherwise, it’s much clearer to simply enumerate them all.