The type `==` in Haskell must be `Eq ab => a & # 8594; b & # 8594; Bool`

The type (==)

is equal Eq a => a -> a -> Bool

, but I can imagine a more general version Eq a b => a -> b -> Bool

, which is false if the types do not match and is the usual kind of equality when the types match. Why is it wrong?

+3


source to share


4 answers


We can define what in terms of Eq

and from . We can compare the types of things to see if they are of the same type. Typeable

Data.Typeable

Typeable

(?==) :: (Eq b, Typeable a, Typeable b) => a -> b -> Bool
x ?== y = cast x == Just y

      

cast

checks that a value of one type is Typeable

actually the same as another. It returns an Just

input if they are the same type or Nothing

if the types are different.



Here are some examples to demonstrate the desired behavior.

> 7 ?== 7
True

> 7 ?== "hello"
False

> 7 ?== 5
False

> (7 :: Int) ?== (7 :: Integer)
False

      

+13


source


(==) :: Eq a b => a -> b -> Bool

will not be as useful as you think.

To define a 2-parameter instance Eq

, you need to know both types (enough to match the instance). Any subscribers of this ==

must either know specifically a

, and b

, or pass the restriction in their interface; then their own callers need to know what a

and b

, or pass the constraint to .... at some point an instance Eq

should be selected rather than exposed through the constraint, and this includes knowing a

and b

at compile time .

At this moment, why should you bother? If you know that a

both are the b

same, then one parameter is enough to compare them Eq

. And if you know they are different, then you know what the answer is False

, and you don't need any instance to tell you that. And if you don't know if they are the same or different, then by definition you don't know enough to select an instance Eq

, so you can't call ==

(or the Eq

-constrained function ) at all!



Thus, it does not help you to get a

and b

unknown types (which implements equality) from individual sources, and then compare them. They would have to merge with an instance Eq a b

, which is actually compile-time proof, whether they are of the same type or not.

The version Typeable

in @Cirdec's answer is very different and much more useful. Here each type supports independentlly Typeable

and one of them supports single parameter Eq

; you can get these two values ​​from two different sources, where you don't know if they are the same or not, but you know that you can check the type of each one; the source a

must know a

well enough to select an instance Typeable

, and the source b

must know b

well enough to select instances of Typeable

and Eq

, but neither source has to know anything about the other type, and neither code must know both types well enough at once, to determine if they are the same (at compile time). 2-parameterEq

causes both types to be known at once, somewhere that would make it almost useless.

+6


source


I think the philosophical answer to your question is that Haskell is similar in nature to mathematics, and when we put on our math hats and define equality for math objects, we usually consider two objects of the same type. For example. look at how equality of equality is defined.

Now, is the set of natural numbers equal to natural? or let go of the wild - the chair is an integer -7? etc. While I am tempted to let my intuition take over and scream "Of course not!", I really can't say that because the question itself is invalid, it's all very undefined. Equality between sets and natural undefined. Equality between chairs and an undefined integer.

Does this mean that you cannot define it? No, go ahead.
But this is not a very popular approach, so choosing a base library is very clear.


In response to your comment, this is correct. As it happens, the sets are so primitive that we can imagine something with them. This is just an example, and I don't know if you agree the same if we choose something else, but let's skate anyway.

In order for the set A to be equal to the set B, we need:

  • Every element from A exists in B
  • Every element from B exists in A

Keeping this very simple, does the set {1,2,3} match 7? I don't know, because saying that the element exists at 7 is undefined, the question is not valid.

But let's take a look at your approach and do as you say: take 7, put it in a pretty dress to lift it up, and call it set C, and even suppose C equals D to show how right you are. Ultimately you are allowed to demand equality between 7 and another set. But I just want you to notice how much work we had to do to get this done in the first place before we can do it. This is what Haskell would like to do, if possible. With sets in mathematics, this is almost always possible.

So, in both Haskell and math, we (still) can't even ask:

(a :: Set) == (7 :: Natural)

      

However, in both Haskell and mathematics, we can first bring it up so that we can look at it differently, and then we can ask:

(liftN :: Natural -> Set) (7 :: Natural) == (a :: Set)

      

Of course, RHS is set C.

And the gist of this answer is that Haskell is just idiomatic in general mathematical terms, defining equality the way he does it.

+2


source


Haskell thinks it makes sense to test the equality of two values ​​of the same type, i.e. checking for equality of two different typed values ​​is pointless and very likely means that you are doing something wrong in your program. This is why type (==) is what it is.

Generally speaking, this is what it means to work in a powerful type system like Haskell's. It is designed for writing better and more meaningful programs.

+1


source







All Articles