Skip to content

Encoding of sums of records #16

@kl0tl

Description

@kl0tl

Sums of records are (de)serialized the same by aeson and this library:

:set -XDeriveGeneric
:set -XDeriveAnyClass
> import Data.Aeson (ToJSON, encode)
> import GHC.Generics (Generic)
> data A = A deriving (Generic, ToJSON)
> data B = B deriving (Generic, ToJSON)
> data D = C1 { f :: A } | C2 { g :: B } deriving (Generic, ToJSON)
> encode $ C1 A
"{\"tag\":\"C1\",\"f\":[]}"
> import Data.Generic.Rep (class Generic)
> import Data.Argonaut (class EncodeJson, encodeJson, stringify)
> import Data.Argonaut.Aeson.Encode.Generic (genericEncodeAeson)
> import Data.Argonaut.Aeson.Options (defaultOptions)
> data A = A
> data B = B
> data D = C1 { f :: A } | C2 { g :: B }
> :paste
… derive instance genericA :: Generic A _
… instance encodeJsonA :: EncodeJson A where
…   encodeJson = genericEncodeAeson defaultOptions
… derive instance genericB :: Generic B _
… instance encodeJsonB :: EncodeJson B where
…   encodeJson = genericEncodeAeson defaultOptions
… derive instance genericD :: Generic D _
… instance encodeJsonD :: EncodeJson D where
…   encodeJson = genericEncodeAeson defaultOptions
… ^D
> stringify $ encodeJson $ C1 { f: A }
"{\"f\":[],\"tag\":\"C1\"}"

but while such data types are perfectly fine in PureScript they are unsafe in Haskell since the declaration of D yields f :: D -> A and g :: D -> B, which are partial.

This can be worked around by wrapping the fields of each constructor in their own type:

data C1Contents = C1Contents { f :: A } deriving (Generic, ToJSON)
data C2Contents = C2Contents { g :: B } deriving (Generic, ToJSON)
data D' = C1' C1Contents | C2' C2Contents deriving (Generic, ToJSON)

but this changes the encoding:

> encode $ C1' $ C1Contents A
"{\"tag\":\"C1'\",\"contents\":{\"f\":[]}}"

I’m aware that we can recover the same encoding in PureScript with newtypes, but would you be open to add to Data.Argonaut.Aeson.Options.SumEncoding a boolean option governing this behaviour?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions