Hi Brian,

You could eliminate the JSON constructor from your servant types by using it in the aeson instance for Foo itself:

    instance ToJSON Foo where
        toJSON = toJSON . JSON

    instance FromJSON Foo where
        parseJSON = fmap (\(JSON t) -> t) . parseJSON

This way, JSON is used only where it's relevant: not in the servant types, but in the aeson instances. It gives the programmer a way to get them for HasStructParser types at pretty much no cost. I don't think duplicate instances are a concern here. If you want to use an existing aeson-equipped type in your servant routes, but redefine those aeson instance via HasStructParser, then make a newtype. In my opinion it's a good idea to have new types for servant inputs anyway, to make very clear the provenance of these values.

Alex

On Sun, May 22, 2016 at 1:05 PM, Brian Hurt <bhurt@spnz.org> wrote:

This is driving me nuts.

So I have a type class HasStructParser I've defined. Details are irrelevant except that if you have HasStructParser defined, then ToJSON is also defined.  So I have:
    instance HasStructParser s => ToJSON s where
        ...

But now, any type that defines ToJSON any other way causes an Overlapping Instances error to happen- the conflict being between the real ToJSON implementation and the one deriving from HasStructParser- this despite the fact that there is no implementation for HasStructParser for the given type.

Now, I don't want to allow Overlapping Instances because if there are *real* overlapping instances, I want that to be an error.  For instance, if a structure did implement HasStructParser and some other implementation of ToJSON, I want to know.

I suppose I could go:

    newtype JSON a = JSON a

    instance HasStructParser s => ToJSON (JSON s) where ...

But this strikes me as being ugly- now I have to add pointless JSON constructors everywhere I want to convert to (or from) JSON.  And this also pollutes my type signatures all over the place- now I can't write a servant endpoint type like:
    :<|> "foo" :> "bar" :> Get '[JSON] [Foo]
I have to write:
    :<|> "foo" :> "bar" :> Get '[JSON] [JSON Foo]

And, of course, if I want to have multiple different types of outputs, now we're off to the races.

So my question is, is there a way to do this without throwing the baby out with the bath water (turning on overloaded instances) or being seriously ugly?  Or am I just screwed?

Brian


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe