简体   繁体   中英

Haskell Eq between different types

I need to use this data structure data D = C Int Float and I need to compare it with an Int, for example a::D == 2 .

How can I create an instance to define this kind of Eq ?

Thank you!

I would implement a projection:

getInt :: D -> Int
getInt (C i _) = i

and then compare with it:

getInt myD == 5

you can even include this into a record:

data D = C { getInt :: Int, getFloat :: Float }

if you like

You can't; == has signature a -> a -> Bool , so it can't be used like this.

Using the convertible package you can define

(~==) :: (Convertible a b, Eq b) => a -> b -> Bool
x ~== y = case safeConvert x of
            Right x' -> x' == y
            Left _ -> False

(==~) :: (Convertible b a, Eq a) => a -> b -> Bool
(==~) = flip (~==)

instance Convertible Int D where ... 
-- or D Int depending on what you have in mind

Without depending on convertible , you could just define a conversion function either from Int to D (and write a == fromInt 2 ) or vice versa.

A less recommended route (for this specific case I think it's simply worse than the first solution) would be to define your own type class, eg

class Eq' a b where
  (=~=) :: a -> b -> Bool

instance Eq a => Eq' a a where
  x =~= y = x == y

instance Eq' D Int where ...

etc.

This can be done, but I doubt you will want to do this. As Alexey mentioned the type of (==) is Eq a=>a->a->Bool , so the only way to make this work would be to make 2 have type D . This may seem absurd at first, but in fact numbers can be made to have any type you want, as long as that type is an instance of Num

instance Num D where
    fromInteger x = C x 1.0

There are still many things to work out, though....

First, you need to fully implement all the functions in Num , including (+) , (*) , abs , signum , fromInteger , and (negate | (-)) .

Ugh!

Second, you have that extra Float to fill in in fromInteger. I chose the value 1.0 above, but that was arbitrary.

Third, you need to actually make D an instance of Eq also, to fill in the actual (==) .

instance Eq D where
    (C x _) == (C y _) = x == y

Note that this is also pretty arbitrary, as I needed to ignore the Float values to get (==) to do what you want it to.

Bottom line is, this would do what you want it to do, but at the cost of abusing the Num type, and the Eq type pretty badly.... The Num type should be reserved for things that you actually would think of as a number, and the Eq type should be reserved for a comparison of two full objects, each part included.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM