Jens Egholm
Jens Egholm

Reputation: 2710

Construction of JSON types in Haskell

I have been toying around with the JSON module for Haskell, and I wanted to manually create some JSON, close to this:

{
  "data": { "unit": "cm" },
  "name": "Hodor"
}

So I tried something like this:

toJSObject [ 
  ("data", toJSObject [ ("unit", toJSString "cm") ]), 
  ("name", toJSString "Hodor")
]

However, I kept getting type mismatches because the data field is of type JSObject JSString, while the name field is of type JSString. Why is it not able to infer the general type JSValue -- both JSObject and JSString should be a subtype. What am I missing?

Thanks in advance!

Upvotes: 3

Views: 357

Answers (1)

Stephen Diehl
Stephen Diehl

Reputation: 8409

As J. Abrahamson pointed out there is no subtype polymorphism in Haskell so you can't represent a list of distinct types. The JSON Value sum type provided by Aeson library ( the de-facto JSON library) can be used for constructing a JSON "heterogeneous" JSON where all values are wrapped up the uniform Value type.

type Object = HashMap Text Value

type Array = Vector Value

-- | A JSON value represented as a Haskell value.
data Value = Object !Object
           | Array !Array
           | String !Text
           | Number !Scientific
           | Bool !Bool
           | Null

Using this we create a type M.HashMap Text Value and wrap it in an Object.

{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson
import qualified Data.HashMap.Strict as M

example :: Value
example = Object $ M.fromList [
    ("data", Object $ M.fromList [ ("unit", "cm") ]),
    ("name", "Hodor")
  ]

main = print $ encode example

Which gives you the lazy bytestring: {"data":{"unit":"cm"},"name":"Hodor"}

Upvotes: 4

Related Questions