Экземпляр Eq имеет некоторые странные сравнения - PullRequest
3 голосов
/ 23 апреля 2011

Я создал модуль обработки изображений, который определяет тип Pixel как Color и Location. Pixel, Color и Location производные Eq, так как я могу захотеть сравнить пиксели между несколькими изображениями.

Eq соответствует моим потребностям при сравнении пикселей, чтобы увидеть, действительно ли они похожи, что я и хотел. Странный побочный эффект экземпляра Eq состоит в том, что сравнение двух непохожих пикселей с одинаковым Location с <= или >= приводит к True, но False для ==, < и >.

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

Затем в ghci некоторые тесты.

>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

Кажется, что мое определение Ord для Pixel повлияло на эти сравнения, что понятно. d показывает, что Location влияет на сравнение. Часть, в которой я запутался, это то, как a является одновременно >= и <= b , не будучи ==, < или >.

РЕДАКТИРОВАТЬ: Если кто-то захочет использовать любой из этого кода, я включу этот фрагмент, который устраняет проблему. Обязательно удалите Eq из определения Pixel.

instance Eq Pixel where
            (Pixel _ a) == (Pixel _ b) = a == b
            (Pixel _ a) /= (Pixel _ b) = a /= b

Это позволяет сравнивать только Location. Наслаждайтесь! :)

Ответы [ 2 ]

9 голосов
/ 23 апреля 2011

Часть, в которой я запутался, это то, как a больше или равно и меньше или равно b, но не равно, меньше или больше.

Представив свой пользовательский экземпляр Ord для Pixel, продолжая при этом выводить Eq, у вас есть интересное следствие:

  • пикселей будут иметь полное структурное равенство в зависимости от их цвета и местоположения
  • однако, чтобы дать им приказ, вы просите игнорировать цвет.

Это заставит вещи вести себя странно, поскольку некоторые вещи будут сравниваться как EQ (на основании наличия только одного и того же местоположения), но в то же время, если вы проверить на равенство с (==), значения будут неравными, так как цвет также включены.

В сущности, вы сделали Eq и Ord экземпляры необоснованными.

Либо получить как Eq, так и Ord, получая полное структурное равенство и упорядочить или вручную написать экземпляр Eq, который отбрасывает информацию о цвете, как ваш существующий экземпляр Ord.

3 голосов
/ 23 апреля 2011

Поскольку ваш экземпляр Ord игнорирует цвет, а ваш производный экземпляр Eq - нет. a == b имеет значение false, поскольку == является методом класса типов Eq, а производный метод будет учитывать цвет.
a <= b имеет значение true, поскольку <= является частью класса типов Ord, а ваша реализация сравнения игнорирует цветчто означает compare a b == EQ , если a и b имеют одинаковое местоположение, независимо от их цвета.

...