问题
In Haskell we have the function (==) :: Eq a => a->a->Bool
which is fine for the large number of datatypes for which an instance of Eq
can be defined. However there are some types for which there is no reasonable way to define an instance of Eq
. one example is the simple function type (a->b)
I am looking for a function that will tell me if two values are actually the same -- not equal but identical.
For example f(id,id)
==> True
f((+),(-))
= False
Clarification:
I don't want to know if two function do the same thing. It is not possible in the general case to do so. I want to know if I've gotten back the same thing I started with. Let me give a stripped down example:
data Foo = Foo (Foo->Foo) --contains a function so no Eq instance
x :: Foo
x = Foo id -- or for that matter Foo undefined
y :: Foo
y = Foo (const x)
a :: Foo
a = let (Foo fy) = y
in fy x
It is clear that by inspection once evaluated, a
will be x
. But let's assume I don't know the function in y but I want to test if the Foo I put in is the same one I got back - that is does fy x
give me x
. How do I do this?
回答1:
One way that wasn't mentioned in Pointer equality in Haskell? is reallyUnsafePtrEquality#. As the name suggests it can be unpredictable and probably should't be used but it can be interesting to see how ghc works. Here's how you can use it in ghci:
> :set -package ghc-prim
> import GHC.Prim
> import GHC.Types
> isTrue# (reallyUnsafePtrEquality# id id)
True
> let a x = x + 2 :: Int
> isTrue# (reallyUnsafePtrEquality# a a)
True
> let b x = x + 2 :: Int
> isTrue# (reallyUnsafePtrEquality# a b)
False
If the function isn't monomorphic it doesn't work:
> let c x = x + 2
> isTrue# (reallyUnsafePtrEquality# c c)
False
Some more examples:
> let d = c in isTrue# (reallyUnsafePtrEquality# d d)
False
> :set -XMonomorphismRestriction
> let d = c in isTrue# (reallyUnsafePtrEquality# d d)
True
You can compare polymorphic types if you wrap them in a newtype:
> :set -XRankNTypes
> newtype X = X (forall a. Num a => a -> a)
> let d = X c
> isTrue# (reallyUnsafePtrEquality# d d)
True
Applying anything makes them not equal
> isTrue# (reallyUnsafePtrEquality# (id ()) (id ()))
False
But when compiling with optimisations this is True
.
Hopefully this is enough to convince you that what you want is a bad idea. One of the solutions in Pointer equality in Haskell? would be a better.
来源:https://stackoverflow.com/questions/30175974/haskell-function-to-check-if-two-values-are-identical