2016-04-21 112 views
1

我需要使用这个数据结构data D = C Int Float,我需要将它与Int进行比较,例如a::D == 2不同类型的Haskell Eq

如何创建一个实例来定义这种Eq?

谢谢!

+0

请注意,因为我不认为你会收到关于此事的通知:我编辑了我的答案以添加更好的解决方案。 –

回答

4

你不能; ==有签名a -> a -> Bool,所以它不能像这样使用。

使用convertible包,你可以定义

(~==) :: (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 

,而不依赖于convertible,你可以只定义转换功能无论是从IntD(写a == fromInt 2),反之亦然。

一个不太推荐的路线(对于这个具体情况,我认为它比第一个解决方案简单得多)将是定义你自己的类型类,例如,

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

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

instance Eq' D Int where ... 

+4

我不认为创建自定义类是一个很好的建议。尤其是对新人来说。 –

+0

@NikitaVolkov我已经有了一个“更合理”的选择,但我已经改写了答案,以添加一个更好的(IMO)解决方案,并把它放在最后。 –

7

我会实现一个投影:

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

,然后用它比较:

getInt myD == 5 

你甚至可以包括到创纪录的:

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

如果你喜欢

1

可以做,但我怀疑你会想这样做。正如阿列克谢提到(==)的类型是Eq a=>a->a->Bool,所以做这项工作的唯一方法就是让2的类型为D。最初,这可能看似荒谬,但实际上可制成数字有你想要的任何类型,只要该类型是Num

instance Num D where 
    fromInteger x = C x 1.0 

的实例还有很多事情需要解决,但.. ..

首先,你需要充分执行Num的所有功能,包括(+)(*)abssignumfromInteger(negate | (-))

呃!

其次,你有那额外的Float来填写fromInteger。我选择了上面的值1.0,但那是任意的。

三,您还需要实际制作D一个Eq的实例,以填写实际的(==)

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

注意,这也是很随意的,因为我需要忽略浮动值,以获得(==)做你希望它是什么。

底线是,这会做你想要做什么,但在滥用Num型的成本,以及Eq型相当严重....的Num型应保留的东西,你居然会考虑为一个数字,并且Eq类型应该保留用于比较两个完整的对象,每个部分都包括在内。