Haskell function to check if two values are identical

让人想犯罪 __ 提交于 2019-12-24 16:42:09

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!