(==)
的类型是 Eq a => a -> a -> Bool
,但我可以想象一个更一般化的版本 Eq a b => a -> b -> Bool
,当类型不匹配时为 false,当类型匹配时仅为通常的相等性。为什么不这样做呢?
(==)
的类型是 Eq a => a -> a -> Bool
,但我可以想象一个更一般化的版本 Eq a b => a -> b -> Bool
,当类型不匹配时为 false,当类型匹配时仅为通常的相等性。为什么不这样做呢?
我们可以通过Eq
和Data.Typeable
来定义它。我们可以比较可Typeable
的对象的类型,以确定它们是否为相同类型。
(?==) :: (Eq b, Typeable a, Typeable b) => a -> b -> Bool
x ?== y = cast x == Just y
cast
检查一个 Typeable
类型的值是否与另一个类型相同。如果它们是相同的类型,则返回输入的 Just
值,否则返回Nothing
。
以下是几个演示期望行为的示例。
> 7 ?== 7
True
> 7 ?== "hello"
False
> 7 ?== 5
False
> (7 :: Int) ?== (7 :: Integer)
False
(==) :: Eq a b => a -> b -> Bool
并不像你想象的那样有用。要确定2参数Eq的实例,您需要了解两种类型,以便匹配实例。任何调用这个“==”的人都需要明确知道“a”和“b”,或者在他们的接口中传递约束;然后他们自己的调用者需要知道“a”和“b”是什么,或者传递约束……在某个时候,必须选择Eq实例,而不是通过约束提供它,这涉及在编译时知道“a”和“b”。此时,为什么要麻烦呢?如果您知道“a”和“b”是相同的,则单参数Eq足以比较它们。如果您知道它们是不同的,则知道答案是“False”,您不需要任何实例来告诉您。如果您不知道它们是否相同或不同,则根据定义,您不知道足够选择Eq实例的信息,因此根本无法调用“==”(或受限制的函数)。因此,这对于从不同来源获取未知类型(实现相等性)的“a”和“b”,然后进行比较将没有帮助。它们必须以“Eq a b”实例的形式一起出现,这实际上是一个编译时的证明,说明它们是否为同一类型。@Cirdec答案中的Typeable版本非常不同,也更有用。在此,每个类型独立支持Typeable,其中一个支持单参数Eq;您可以从两个不同的源获取这两个值,在那里您不知道它们是否相同,但您知道可以检查每个类型;“a”源必须了解“a”,以选择Typeable实例,“b”源必须了解“b”以选择Typeable和Eq实例,但是没有任何代码需要同时充分了解两种类型以告诉它们是否相同(在编译时)。2参数Eq强制同时了解两种类型,这将使其接近无效。?==
),否则它们涉及在运行时传递两个额外的字典。 - dfeuer(a :: Set) == (7 :: Natural)
然而,在Haskell和数学中,我们可以先提升它,以便我们可以以不同的方式查看它,然后我们可以问:
(liftN :: Natural -> Set) (7 :: Natural) == (a :: Set)
当然,右手边的集合C就是RHS。
这个答案的重点在于,Haskell通过以常见的数学术语定义相等性的方式,仅仅是在表达惯用语。