The fact that you cannot automatically get this instance is 100% correct behavior. The reason that what you expect does not work is that there is no way to find out that an FromJSON (Map Text v) instance FromJSON (Map Text v) can be used for values ββlike Map MyText v . This is because the creation and manipulation of Map based on the Ord instance of its key, and there is no way (for the compiler) to know that for all xy (x == y) == (MyText x == MyText y) , which are necessary for Map MyText v Map Text v to Map MyText v . More technically, a Map role declaration:
type role Map nominal representational
In fact, this suggests that Map kv is only coercible for other maps, the first parameter of which is identical. Vicki says:
we have an instance of Coercible ab => Coercible (T a) (T b) if and only if the first parameter has a representative role.
The Coercible class Coercible used to create safe enforcement types in recent versions of GHC (7.8?). For more information on type roles and their role in type safety, see here .
If you plan to output an instance for Ord MyText , it is really safe to force Map Text v to Map MyText v , since the Ord instance is the same. This requires the use of unsafeCoerce . You should still write the instance yourself:
instance ToJSON v => ToJSON (Map MyText v) where toJSON = toJSON . (unsafeCoerce :: Map MyText v -> Map Text v) instance FromJSON v => FromJSON (Map MyText v) where parseJSON = (unsafeCoerce :: Parser (Map Text v) -> Parser (Map MyText v)) . parseJSON
If you plan to write your own copy of Ord , this is completely unsafe. Your decision is correct, but not very effective. Use the following:
toJSON = toJSON . M.mapKeys (coerce :: MyText -> Text) parseJSON = fmap (M.mapKeys (coerce :: Text -> MyText)) . parseJSON
Depending on your Ord instance, you might use mapKeysMonotonic instead, which would be more efficient. See the Data.Map Documentation exactly when you can use mapKeysMonotonic .
Then the obvious things will work:
data Bar = Bar deriving (Eq, Ord, Generic) instance ToJSON Bar instance FromJSON Bar data Foo = Foo (Map MyText Bar) deriving (Generic) instance ToJSON Foo instance FromJSON Foo -- Using GeneralizedNewtypeDeriving newtype Foo2 = Foo2 (Map MyText Bar) deriving (FromJSON, ToJSON)
Full code:
{-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving, FlexibleInstances #-} module Test where import Data.Aeson import GHC.Generics (Generic) import qualified Data.Map as M import Data.Map (Map) import Data.Text (Text) import GHC.Prim (coerce) import Unsafe.Coerce (unsafeCoerce) import Data.Aeson.Types (Parser) newtype MyText = MyText {unMyText::Text} deriving (Eq, Ord, Generic, ToJSON, FromJSON) instance ToJSON v => ToJSON (Map MyText v) where -- toJSON = toJSON . M.mapKeys (coerce :: MyText -> Text) toJSON = toJSON . (unsafeCoerce :: Map MyText v -> Map Text v) instance FromJSON v => FromJSON (Map MyText v) where -- parseJSON x = fmap (M.mapKeys (coerce :: Text -> MyText)) (parseJSON x) parseJSON x = (unsafeCoerce :: Parser (Map Text v) -> Parser (Map MyText v)) (parseJSON x) data Bar = Bar deriving (Eq, Ord, Generic) instance ToJSON Bar instance FromJSON Bar data Foo = Foo (Map MyText Bar) deriving (Generic) instance ToJSON Foo instance FromJSON Foo newtype Foo2 = Foo2 (Map MyText Bar) deriving (FromJSON, ToJSON)