7

I would like to use derived instance like this:

data Test3D = forall a. (Show a, Eq a, Typeable a, Generic a)
                => Test3D { testDt :: String
                          , testPrm :: a
                          }
   deriving (Show, Eq, Typeable, Generic)

instance Binary (Test3D)
$(deriveJSON defaultOptions ''Test3D)

But I received from GHC:

• Can't make a derived instance of ‘Show Test3D’:
        Constructor ‘Test3D’ has existentials or constraints in its type
        Possible fix: use a standalone deriving declaration instead
• In the data declaration for ‘Test3D’

This way is very convenient for my project. I can not find the solution.

Is any way of using derived instance for such data?

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
QSpider
  • 537
  • 2
  • 10
  • 2
    How would you write the instance yourself? Even writing out the type signature will prove difficult, if you want to show any information about the `testPrm`. If you can't figure out how to do it, then GHC can't do it automatically for you. On the other hand, if you don't care about showing `testPrm`, then the instance is easy to write by hand and you don't need to derive it. – amalloy Sep 04 '17 at 07:52
  • 2
    This involves writing a `Binary` instance for every `Generic`. It looks as a rather complex task. I think we can't realistically hope that the automagic deriving mechanism solved this for us. Perhaps we could manually write an easier instance if we use `Binary a` instead of `Generic a`? – chi Sep 04 '17 at 08:40
  • Maybe I'm not correctly implementing my idea. I just want to have some type of data, which in turn contains a field with an unknown type. But the field type meets a certain requirement through type classes. And all of them should be (Show a, Eq a, Typeable a, Generic, ...). – QSpider Sep 04 '17 at 09:58

1 Answers1

9

Is any way of using derived instance for such data?

Yes. Do what GHC suggested, make a standalone deriving clause:

{-# LANGUAGE StandaloneDeriving, ExistentialQuantification #-}

data Test3D = forall a. (Show a)
                => Test3D { testDt :: String
                          , testPrm :: a
                          }

deriving instance Show Test3D

What you cannot do is derive an Eq instance, because different values may actually contain different types and it's only possible to compare these with a dynamic-cast hack through Typeable.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319