1

First of all, I want to clarify that I've tried to find a solution to my problem googling but I didn't succeed.

I need a way to compare two expressions. The problem is that these expressions are not comparable. I'm coming from Erlang, where I can do :

case exp1 of 
     exp2 -> ...

where exp1 and exp2 are bound. But Haskell doesn't allow me to do this. However, in Haskell I could compare using ==. Unfortunately, their type is not member of the class Eq. Of course, both expressions are unknown until runtime, so I can't write a static pattern in the source code.

How could compare this two expressions without having to define my own comparison function? I suppose that pattern matching could be used here in some way (as in Erlang), but I don't know how.

Edit

I think that explaining my goal could help to understand the problem.

I'm modyfing an Abstract Syntax Tree (AST). I am going to apply a set of rules that are going to modify this AST, but I want to store the modifications in a list. The elements of this list should be a tuple with the original piece of the AST and its modification. So the last step is to for each tuple search for a piece of the AST that is exactly the same, and substitute it by the second element of the tuple. So, I will need something like this:

 change (old,new):t piece_of_ast =
     case piece_of_ast of 
          old -> new
          _ -> piece_of_ast

I hope this explanation clarify my problem.

Thanks in advance

  • 2
    What stops you from defining an `Eq` instance? – Zeta Oct 20 '14 at 17:55
  • I have not defined these types. They are defined in a library. Independently they have a lot of constructors, and subtypes, etc. – Salvador Tamarit Oct 20 '14 at 17:57
  • 1
    It's a little unclear exactly what you're doing. You don't necessarily need an `Eq` instance if you can use pattern matching. Could you show a more concrete example? – bheklilr Oct 20 '14 at 17:59
  • @bheklilr I hope now, with this explanation you can understand better my problem. – Salvador Tamarit Oct 20 '14 at 18:10
  • @SalvadorTamarit Can you provide a link to the library if it's open source? If there are simply a large number of constructors but there's nothing stopping you from checking for syntactic equality (such as HOAS), then really there should be a `deriving Eq` – daniel gratzer Oct 20 '14 at 18:12
  • You can't pattern-match like that. You're just shadowing the name `old`. It looks like you need `Eq`. – Christian Conkle Oct 20 '14 at 18:12
  • @jozefg The library is the following: http://hackage.haskell.org/package/language-c-0.4.6 The most interesting module is this one: http://hackage.haskell.org/package/language-c-0.4.6/docs/Language-C-Syntax-AST.html And I need to compare elements of CStatement – Salvador Tamarit Oct 20 '14 at 18:15
  • Hang on a second, just how do you store the old and new pieces in a list? What's the type of that list? That said, it seems all the types in the second module have `Data` instances available, and then you could cobble together something using `geq` in package [Data.Generics.Twins](https://hackage.haskell.org/package/syb-0.4.2/docs/Data-Generics-Twins.html) I guess. – yatima2975 Oct 20 '14 at 18:24
  • @yatima2975 The type is [(Cstat,Cstat)]. Indeed, I'm using the generics package for the AST traversal. Thanks for your help. geq is perfect. It solves my problem. However, I wonder what would happen if they didn't be from class Data neither Eq. – Salvador Tamarit Oct 20 '14 at 18:41
  • I believe that the original core of this question is the same as this question: [Pattern matching identical values](http://stackoverflow.com/questions/1179008/pattern-matching-identical-values). The answers there explain that the inability to pattern-match on "two identical values" without `Eq` was intentionally left out of Haskell. – Christian Conkle Dec 25 '14 at 06:41

2 Answers2

1

It's probably an oversight in the library (but maybe I'm missing a subtle reason why Eq is a bad idea!) and I would contact the maintainer to get the needed Eq instances added in.

But for the record and the meantime, here's what you can do if the type you want to compare for equality doesn't have an instance for Eq, but does have one for Data - as is the case in your question.

The Data.Generics.Twins package offers a generic version of equality, with type

geq :: Data a => a -> a -> Bool

As the documentation states, this is 'Generic equality: an alternative to "deriving Eq" '. It works by comparing the toplevel constructors and if they are the same continues on to the subterms.

Since the Data class inherits from Typeable, you could even write a function like

veryGenericEq :: (Data a, Data b) => a -> b -> Bool
veryGenericEq a b = case (cast a) of
    Nothing -> False
    Maybe a' -> geq a' b

but I'm not sure this is a good idea - it certainly is unhaskelly, smashing all types into one big happy universe :-)


If you don't have a Data instance either, but the data type is simple enough that comparing for equality is 100% straightforward then StandaloneDeriving is the way to go, as @ChristianConkle indicates. To do this you need to add a {-# LANGUAGE StandaloneDeriving #-} pragma at the top of your file and add a number of clauses

deriving instance Eq a => Eq (CStatement a)

one for each type CStatement uses that doesn't have an Eq instance, like CAttribute. GHC will complain about each one you need, so you don't have to trawl through the source.

This will create a bunch of so-called 'orphan instances.' Normally, an instance like instance C T where will be defined in either the module that defines C or the module that defines T. Your instances are 'orphans' because they're separated from their 'parents.' Orphan instances can be bad because you might start using a new library which also has those instances defined; which instance should the compiler use? There's a little note on the Haskell wiki about this issue. If you're not publishing a library for others to use, it's fine; it's your problem and you can deal with it. It's also fine for testing; if you can implement Eq, then the library maintainer can probably include deriving Eq in the library itself, solving your problem.

Christian Conkle
  • 5,932
  • 1
  • 28
  • 52
yatima2975
  • 6,580
  • 21
  • 42
  • 1
    I think this is a better answer than mine, not least because it actually answers the question. I think the `StandaloneDeriving` solution is actually better (less of a hack) in this case, though, assuming it works. I'd put it first in the answer. As you illustrate, `Data` gets you way way into the weeds of unidiomatic Haskell very quickly. `a -> b -> Bool`?! Eew. – Christian Conkle Oct 20 '14 at 19:26
  • 1
    A cautionary note about [orphan instances](http://www.haskell.org/haskellwiki/Orphan_instance) is probably appropriate, especially because the asker seems to be new to Haskell. (And interested in Haskell's quirks...) – Christian Conkle Oct 20 '14 at 19:29
  • @ChristianConkle the neatest solution would indeed be `StandaloneDeriving` plus selective import of instances, but we don't have that in the language/GHC (yet?). I already mention something about orphan instances at the end but am very open to edits with stronger phrasing and/or copious use of the color red! – yatima2975 Oct 20 '14 at 19:32
  • Thanks @yatima2975, for solving my problem. – Salvador Tamarit Oct 20 '14 at 22:24
0

I'm not familiar with Erlang, but Haskell does not assume that all expressions can be compared for equality. Consider, for instance, undefined == undefined or undefined == let x = x in x.

Equality testing with (==) is an operation on values. Values of some types are simply not comparable. Consider, for instance, two values of type IO String: return "s" and getLine. Are they equal? What if you run the program and type "s"?

On the other hand, consider this:

f :: IO Bool
f = do
      x <- return "s" -- note that using return like this is pointless
      y <- getLine
      return (x == y) -- both x and y have type String.

It's not clear what you're looking for. Pattern matching may be the answer, but if you're using a library type that's not an instance of Eq, the likely answer is that comparing two values is actually impossible (or that the library author has for some reason decided to impose that restriction).

What types, specifically, are you trying to compare?

Edit: As a commenter mentioned, you can also compare using Data. I don't know if that is easier for you in this situation, but to me it is unidiomatic; a hack.

You also asked why Haskell can't do "this sort of thing" automatically. There are a few reasons. In part it's historical; in part it's that, with deriving, Eq satisfies most needs.

But there's also an important principle in play: the public interface of a type ideally represents what you can actually do with values of that type. Your specific type is a bad example, because it exposes all its constructors, and it really looks like there should be an Eq instance for it. But there are many other libraries that do not expose the implementation of their types, and instead require you to use provided functions (and class instances). Haskell allows that abstraction; a library author can rely on the fact that a consumer can't muck about with implementation details (at least without using unsafe tools like unsafeCoerce).

Christian Conkle
  • 5,932
  • 1
  • 28
  • 52
  • The library is the following: http://hackage.haskell.org/package/language-c-0.4.6 The most interesting module is this one: http://hackage.haskell.org/package/language-c-0.4.6/docs/Language-C-Syntax-AST.html And I need to compare elements of CStatement – Salvador Tamarit Oct 20 '14 at 18:18
  • 1
    Oh dear. It looks at first glance like an instance `Eq a => Eq (CStatement a)` could be written or derived. You might experiment with `StandaloneDeriving`; you'll probably need orphan instances for `CStatement`, `CExpression`, and a bunch of other types; GHC will tell you. You may also consider discussing the issue with the maintainers of the library. – Christian Conkle Oct 20 '14 at 18:30
  • It seems that it exists an easier solution in this case as @yatima2975 suggested. Using geq in library [Data.Generics.Twins](https://hackage.haskell.org/package/syb-0.4.2/docs/Data-Generics-Twins.html). Your approach can also work. However, it is very surprising to me that there is no way to define a kind of "dynamic pattern" in Haskell, and one has to rely in deriving class Eq each time. – Salvador Tamarit Oct 20 '14 at 18:50
  • Thanks @ChristianConkle for clarify the problem an provide an interesting alternative. However, I still don't understand why, in case of a _private interface_, this kind of matching would have not sense (according GHC). One can be no interested in knowing the implementation of a data structure, but can be interested in compare two different instances, independently that the result had any sense or not. Of course that by deriving `Eq` it provides the expected result. I mean, if at the end it is possible to do _ugly_ things, why not allow them directly? And I don't think this is so _ugly_ :) – Salvador Tamarit Oct 20 '14 at 22:26
  • I am still not completely convinced, but [this post](http://stackoverflow.com/questions/10956419/why-isnt-every-type-part-of-eq-in-haskell) has helped me to understand it a little better. – Salvador Tamarit Oct 20 '14 at 22:36