1

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?

John F. Miller
  • 26,961
  • 10
  • 71
  • 121
  • 1
    Maybe the same question as this? http://stackoverflow.com/questions/1717553/pointer-equality-in-haskell – Ryoichiro Oka May 11 '15 at 19:29
  • 14
    I am almost sure you don't actually want this. – Cubic May 11 '15 at 19:32
  • 2
    Values in pure functional programming have no identity like OOP objects. – chi May 11 '15 at 19:40
  • It is nigh on impossible to compare two functions in Haskell. For instance, `Control.Applicative.<*>` and `Control.Monad.ap` are pretty much identical, but are incomparable because of their types. – AJF May 11 '15 at 20:14
  • What would you want the result of, say, `f (\x -> x+x) (\x -> 2*x)` to be? – leftaroundabout May 11 '15 at 21:12
  • If you solve the halting problem for me, I will solve this problem for you. – Rein Henrichs May 12 '15 at 18:22
  • Leftroundabout: False. They are not the same function. Rein Henrichs, it is my inability to solve the halting problem that leads to my question. I have a data structure that includes a function so I cannot create an Eq class for it. They form a graph, and I need to know if I've looped back to the node I started from. – John F. Miller May 14 '15 at 07:14

1 Answers1

10

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.

Community
  • 1
  • 1
cchalmers
  • 2,896
  • 1
  • 11
  • 11
  • @Sibi Right, my understanding is for `c :: Num a => a -> a`, `a` gets defaulted to `Integer` by ghci's default rules (because it needs to have some type). This means `c` gets "cloned" at each site and so they have different pointer values. On the other hand `id` doesn't need to select a specific type so it points to the same thing. – cchalmers May 11 '15 at 21:36