开发者

Eq instance has some strange comparisons

开发者 https://www.devze.com 2023-02-28 13:11 出处:网络
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.

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! :)


The part I'm confused about is how a is both greater than or equal to and less than or equal to b without being equal, less than, or greater.

By introducing your custom Ord instance for Pixel, while still deriving Eq, you have an interesting consequence:

  • pixels will have full structural equality, based on both their color and location
  • however, to give them an ordering, you ask to ignore the color.

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 you test for equality with (==), the values will be inequal, since the color is also included.

Essentially you've made the Eq and Ord instances unsound.

Either derive both Eq and Ord, getting full structural equality and ordering, or manually write an Eq instance that discards color information, as your existing Ord instance does.


Because your Ord instance ignores color but your derived Eq instance will not. a == b is false because == is a method of the Eq typeclass and the derived method will account for color.
a <= b is true because <= is part of the Ord typeclass and your implementation of compare ignores color which means compare a b == EQ if a and b have the same Location, regardless of their Color.

0

精彩评论

暂无评论...
验证码 换一张
取 消