How to write a aeson ToJSON instances by hand for a polymorphic type like:
data Show a => Translatable a = Translatable (Map.Map String a)
deriving (Show, Eq, Typeable)
I would like to encode a
Translatable $ Map.fromList [("key", "value"), ("key2", "value2")]
to a json object like
{ "key", "value", "key2", "value2" }
What I tried so far is this:
import qualified Data.Aeson as A
import Data.Data (Typeable)
import qualified Data.Map as Map
data Show a => Translatable a = Translatable (Map.Map String a)
deriving (Show, Eq, Typeable)
instance Show a => A.ToJSON (Translatable a) where
toEncoding xs = A.object $ map (.=) (Map.toList xs)
Error
Couldn't match type ‘A.Value’
with ‘Data.Aeson.Encoding.Internal.Encoding' A.Value’
Expected type: A.Encoding
Actual type: A.Value
The aeson documentation showes:
type Encoding = Encoding' Value
But A.Encoding' is not in scope
Not in scope: data constructor ‘A.Encoding'’
what am I doing wrong?
I changed my Translatable to a type
type Translatable a = Map.Map String a
And now it works without adding Translatable as instance to ToJSON
But the initial question is still the question.
You are mixing the toJSON
and toEncoding
functions up. Just implement the toJSON
function of your ToJSON
instance. I imported Data.Aeson
unqualified, to have less of a struggle with the operators.
import Data.Aeson
import qualified Data.Text as T
--- etc.
instance Show a => ToJSON (Translatable a) where
toJSON (Translatable myMap) = toJSON
[ object [ T.pack key .= show val ] | (key, val) <- Map.toList myMap ]
We use the toJSON
function on a list of json objects to create a json array. T.pack key
is needed, since your map keys are String
s, but .=
needs a Text
.