Recording an instance of the form `(forall a. Class a => Class (fa)) => Class (Type f)`

I am performing the default resolution in one of my programs, performing a natural conversion from MyType Maybeto MyType Identity. I want to get an instance ToJSONfor these types. I know that Maybeand Identityhave instances of ToJSON a => ToJSON (Maybe a)and ToJSON a => ToJSON (Identity a).

I would like to declare an instance of the following form:

instance (forall a . ToJSON a => ToJSON (f a)) => ToJSON (MyType f)

This seems like a reasonable request to get into the type system. I want to demonstrate an instance ToJSONfor MyType f, provided that I can always get ToJSON (f a)for everyone ToJSON a. In a logical notation, this suggests that I can demonstrate (P (a) ⇒ P (f (a))) ⇒ P (h (f)) for some property P. This seems to me well formed.

Unfortunately, I get the following syntax error as is:

• Illegal polymorphic type: forall a. ToJSON a => ToJSON (f a)
  A constraint must be a monotype
• In the context: (forall a. ToJSON a => ToJSON (f a))
  While checking an instance declaration
  In the instance declaration for ‘ToJSON (GpgParams f)’

The QuantifiedConstraints suggestion seems to provide this syntax, but it has not yet been implemented.

I can try to get around this limitation by implementing my own class JSONable.

class JSONable f where
  jsonize :: f a -> Value

  default jsonize :: (ToJSON a, ToJSON (f a)) => f a -> Value
  jsonize = toJSON

Unfortunately, this means giving up all the functions of the standard library, which requires a limitation ToJSON.

As far as I can tell, the best compromise in this case is to simply refuse and write explicit instances for:

instance ToJSON (MyType Maybe)
instance ToJSON (MyType Identity)

Is it true that it is as strong as language? Is the desired case just badly formed? Or is it actually possible to declare such an instance in Haskell for an existing class?

+6
source share
1

QuantifiedConstraints forall a. ToJSON a => ToJSON (f a), , , , ToJSON.

forall a. ToJSON a => ToJSON (f a) f: . , aeson ToJSON1.

class ToJSON1 f where  -- encoding of `forall a. ToJSON a => ToJSON (f a)`
  ...

toJSON1 :: (ToJSON1 f, ToJSON a) => f a -> Value

- f ToJSON1 F, , ToJSON

instance ToJSON a => ToJSON (F a) where
  toJSON = toJSON1

, ToJSON1 F forall a. ToJSON a => ToJSON1 (F a).

, aeson, - ToJSON (f a), ToJSON1 F ToJSON a, , newtype ( Identity):

newtype Id1 f a = Id1 { unId1 :: f a }

instance (ToJSON1 f, ToJSON a) => ToJSON (Id1 f a) where
  toJSON = toJSON1 . unId1

, ToJSON (MyType f), coerce :: MyType f -> MyType (Id1 f).

import Data.Coerce

instance ToJSON1 f => ToJSON (MyType f) where
  toJSON = (...) . (coerce :: MyType f -> MyType (Id1 f))
    {- in "(...)" we can use functions that require "ToJSON (Id1 f a)", which is informally equivalent to "ToJSON (f a)" -}
+9

All Articles