I have made an image processing module that defines a Pixel type as a Color and Location. Pixel, Color, and Location derive Eq, as I may want to compare pixels between multiple images.
Eq suits my needs for comparing pixels to see if they’re exactly alike, which is what I wanted. A strange side effect of instancing Eq is that comparing 2 unlike pixels with the same Location with either <= or >= results in True, but False for ==, <, and >.
data Color = Color { red :: Int
, green :: Int
, blue :: Int
, alpha :: Int
} deriving ( Show, Eq )
data Location = Location { x :: Int
, y :: Int
} deriving ( Show, Eq, Ord )
data Pixel = Pixel { color :: Color
, location :: Location
} deriving ( Show, Eq )
instance Ord Pixel where
compare (Pixel _ a) (Pixel _ b) = compare a b
Then in ghci some tests.
>let a = Pixel (Color 0 0 0 255) (Location 0 0)
>let b = Pixel (Color 0 0 1 255) (Location 0 0)
>let c = Pixel (Color 0 0 0 255) (Location 0 0)
>let d = Pixel (Color 0 0 0 255) (Location 0 1)
>a == b
False
>a /= b
True
>a < b
False
>a > b
False
>a <= b
True
>a >= b
True
>a == c
True
>a /= c
False
>a > c
False
>a < c
False
>a >= c
True
>a <= c
True
>a == d
False
>a /= d
True
>a > d
False
>a < d
True
a >= d
False
a <= d
True
It seems that my defining Ord for a Pixel has affected these comparisons, which is understandable. d shows that Location affects comparison. The part I’m confused about is how a is both >= and <= b without being ==, <, or >.
EDIT: In case anyone wants to use any of this code, I’ll include this snippet that fixes the problem. Be sure to remove Eq from the Pixel definition.
instance Eq Pixel where
(Pixel _ a) == (Pixel _ b) = a == b
(Pixel _ a) /= (Pixel _ b) = a /= b
This allows for comparison for Location only. Enjoy! 🙂
By introducing your custom
Ordinstance forPixel, while still derivingEq, you have an interesting consequence:This is going to make things behave strangely, as some things will compare as
EQ(based on having the same location only), while at the same time, if youtest for equality with
(==), the values will be inequal, since the color isalso included.
Essentially you’ve made the
EqandOrdinstances unsound.Either derive both
EqandOrd, getting full structural equality andordering, or manually write an
Eqinstance that discards color information,as your existing
Ordinstance does.