2

I'm parsing a third party JSON structure into my own set of types. I'd like to parse in the most efficient way possible (I'm parsing data sent over a unix socket with Network.Socket)

Aeson's documentation claims that parsing with toEncoding yields up to a 3x speedup over toJSON, however I don't understand how to write a valid instance using toEncoding for my simple sum type.

for example:

data NodeLayout =
    SplitHorizontalLayout
    | SplitVerticalLayout
    | StackedLayout
    | TabbedLayout
    | DockAreaLayout
    | OutputLayout
    deriving (Eq, Generic)

instance ToJSON NodeLayout where
    toJSON = \case
        SplitHorizontalLayout -> "splith"
        SplitVerticalLayout   -> "splitv"
        StackedLayout         -> "stacked"
        TabbedLayout          -> "tabbed"
        DockAreaLayout        -> "dockarea"
        OutputLayout          -> "output"

instance FromJSON NodeLayout where
    parseJSON (String s) = pure $ case s of
        "splith"   -> SplitHorizontalLayout
        "splitv"   -> SplitVerticalLayout
        "stacked"  -> StackedLayout
        "tabbed"   -> TabbedLayout
        "dockarea" -> DockAreaLayout
        "output"   -> OutputLayout
        _          -> error "Received unrecognized NodeLayout"
    parseJSON _ = error "Error parsing NodeLayout"

I have other data types that will receive Vectors of this, but sometimes I receive a single value that needs to be parsed individually. How does one efficiently parse strings into sum types using toEncoding?

user51
  • 8,843
  • 21
  • 79
  • 158
leshow
  • 1,568
  • 2
  • 15
  • 30

1 Answers1

3

As far as I know, Aeson does not provide an alternative to fromJSON for parsing / decoding. The docs explain that toEncoding allows more efficient encoding / serialization - going from the Haskell in-memory representation to the wire format. It's not clear from your question which direction you require to be fast.

You can provide an explicit toEncoding following the pattern of your toJSON. Data.Aeson.Encoding provides a bunch of helper functions for writing these:

    toEncoding = \case
        SplitHorizontalLayout -> text "splith"
        SplitVerticalLayout   -> text "splitv"
        StackedLayout         -> text "stacked"
        TabbedLayout          -> text "tabbed"
        DockAreaLayout        -> text "dockarea"
        OutputLayout          -> text "output"
bergey
  • 3,041
  • 11
  • 17
  • Both preferably – leshow Mar 05 '19 at 21:24
  • Is there a way to write the FromJSON instance in a way that would be more efficient? – leshow Mar 05 '19 at 21:30
  • 1
    You shouldn't need to use `.Internal` module, Public https://hackage.haskell.org/package/aeson-1.4.2.0/docs/Data-Aeson-Encoding.html is enough. If it's not, please open an issue, so we can discuss. – phadej Mar 06 '19 at 00:43
  • 2
    There are no way to write different (more efficient or not) `FromJSON` instances. There might be if there's luck with GSoC 2019. See https://summer.haskell.org/ideas.html#tokenstream-json-parsing – phadej Mar 06 '19 at 00:44
  • Thank you @phadej for your additional information. `text` is also exported from Data.Aeson.Encoding, so no problems there either. – leshow Mar 06 '19 at 14:37
  • Thanks @phadej, I updated the link above. Glad to see the GSOC idea also. – bergey Mar 06 '19 at 19:08