Skip to content

Improve errors for recursively-defined type class instances #2975

@cdepillabout

Description

@cdepillabout

Given the following Foo type:

data Foo = Foo
  { int :: Int
  , foo :: Maybe Foo
  }

I can derive Generic like the following:

derive instance genericFoo :: Generic Foo _

I can even write an instance of Eq for Foo by hand:

instance eqFoo :: Eq Foo where
  eq :: Foo -> Foo -> Boolean
  eq (Foo fooA) (Foo fooB) =
    fooA.int == fooB.int && fooA.foo == fooB.foo

However, I get an error when trying to use genericEq to write the Eq instance:

instance eqFoo :: Eq Foo where eq = genericEq

The error is as follows:

[1/1 CycleInDeclaration] src/Web/Twitter/Test.purs:19:1

  19  instance eqFoo :: Eq Foo where eq = genericEq
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  The value of eqFoo is undefined here, so this reference is not allowed.

Is this a deficiency in the compiler? Or simply a short-coming of Generic? Or maybe just a limitation with recursive types in a strict language?

If this is a limitation with Generic and not a compiler issue, it would be nice to get a better error message from the compiler. I didn't really understand what the error message was talking about until I played around with the code a little:

The value of eqFoo is undefined here, so this reference is not allowed.

I mean, it makes sense now that I know what it is talking about, but it would have been more clear/obvious if it said something like:

It is not possible to use genericEq with Foo because Foo is a recursive datatype.


Here is a repository with some code to play around with if you want to reproduce the issue:

https://github.com/cdepillabout/purescript-twitter-types/blob/16b5cfe7a55d1f23d12f6b87766abff31bf665ad/src/Web/Twitter/Test.purs

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions