haskell - Automatic derivation of ToJSON for (Map NewtypeOfText v) -



haskell - Automatic derivation of ToJSON for (Map NewtypeOfText v) -

i have map key newtype of text. automatically (as much possible) derive tojson , fromjson map. aeson has instances tojson , fromjson map text v.

my verbose code works:

{-# language derivegeneric #-} module test import classyprelude import data.aeson import ghc.generics (generic) import qualified data.map m newtype mytext = mytext {unmytext::text} deriving (eq, ord) info bar = bar deriving (generic) instance tojson bar instance fromjson bar info foo = foo (map mytext bar) instance tojson foo tojson (foo x) = tojson mp mp = m.fromlist . map (\(x,y) -> (unmytext x,y)) . m.tolist $ x instance fromjson foo parsejson v = convert <$> parsejson v convert :: map text bar -> foo convert = foo . mapfromlist . map (\(x,y) -> (mytext x,y)) . maptolist

can more following?

data foo = foo (map mytext bar) deriving (generic) instance tojson foo instance fromjson foo edit

i tried (but still no luck):

newtype mytext = mytext {unmytext::text} deriving (eq, ord, tojson, fromjson) instance tojson foo tojson (foo x) = tojson x

and

newtype mytext = mytext {unmytext::text} deriving (eq, ord, tojson, fromjson) instance tojson foo

the fact can't automatically derive instance 100% right behavior. reason expect doesn't work there no way know instance fromjson (map text v) can used on values of type map mytext v. because creation , manipulation of map predicated on ord instance of key, , there no way (for compiler) know x y (x == y) == (mytext x == mytext y), required safely coerce map text v map mytext v. more technically, role declaration of map is:

type role map nominal representational

essentially says map k v coercible other maps first type parameter identical. wiki says:

we have instance coercible b => coercible (t a) (t b) if , if first parameter has representational role.

the class coercible used type safe coercions in recent versions of ghc (7.8?) more info type roles , role in type safety, see here.

if plan derive instance ord mytext, indeed safe coerce map text v map mytext v, since ord instance same. requires utilize of unsafecoerce. still have write instance yourself, though:

instance tojson v => tojson (map mytext v) tojson = tojson . (unsafecoerce :: map mytext v -> map text v) instance fromjson v => fromjson (map mytext v) parsejson = (unsafecoerce :: parser (map text v) -> parser (map mytext v)) . parsejson

if plan write own ord instance, above absolutely not safe. solution correct, not efficient. utilize following:

tojson = tojson . m.mapkeys (coerce :: mytext -> text) parsejson = fmap (m.mapkeys (coerce :: text -> mytext)) . parsejson

depending on ord instance, may able utilize mapkeysmonotonic instead, more efficient. see documentation of data.map exactly when can utilize mapkeysmonotonic.

then, obvious things work:

data bar = bar deriving (eq, ord, generic) instance tojson bar instance fromjson bar info 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 import data.aeson import ghc.generics (generic) import qualified data.map 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) -- tojson = tojson . m.mapkeys (coerce :: mytext -> text) tojson = tojson . (unsafecoerce :: map mytext v -> map text v) instance fromjson v => fromjson (map mytext v) -- parsejson x = fmap (m.mapkeys (coerce :: text -> mytext)) (parsejson x) parsejson x = (unsafecoerce :: parser (map text v) -> parser (map mytext v)) (parsejson x) info bar = bar deriving (eq, ord, generic) instance tojson bar instance fromjson bar info foo = foo (map mytext bar) deriving (generic) instance tojson foo instance fromjson foo newtype foo2 = foo2 (map mytext bar) deriving (fromjson, tojson)

haskell aeson

Comments

Popular posts from this blog

Delphi change the assembly code of a running process -

json - Hibernate and Jackson (java.lang.IllegalStateException: Cannot call sendError() after the response has been committed) -

C++ 11 "class" keyword -