Please ignore the first post and jump straight to my update Help with decoding tagged JSON needed
I’m trying to reduce boilerplate code without compromising on type safety. The data I’m dealing with consists of lots of records which all have at least one field in common, type
, such as
[
{ "type": "foo" },
{ "type": "bar" }
]
I would like to create a sum type, where the constructors represent each possible type of node. My first version consisted of a record where the “type” could be specified with a type argument.
type Node nodeType dataValuesType r
= { nodeType :: nodeType
| r
}
This let me create data types with only a single constructor and no arguments…
data FooType = FooType
…and use those to create variations of the JSON records, like this:
data MyNode = Node FooType ()
What’s left is to implement readImpl
from Simple JSON…
expectString ::
forall a.
String -> -- | nodeType value we're looking for
a -> -- | Constructor function
Foreign -> -- | nodeType value we're decoding
F a
expectString query consFn f = do
s <- readString f
if s == query then
pure consFn
else
fail <<< ForeignError $ "expected hyperlink but got: " <> s
instance readForeignFooType :: JSON.ReadForeign FooType where
readImpl = expectString "foo" FooType
and things will just work (I’m using generics to generate the decoding code for the actual sum type as outlined in the Simple JSON docs)`. I get nodes where I can easily pattern match on constructors and so on. But the whole process involves a lot of typing and I’m sure I’m doing this wrong.
I have this vague idea that I should be able to use something like a Symbol
and move all of the decoding into my generic Node
type rather than repeat this “check if string is this or that” logic everywhere where I’m using Node
.
I’ve tried various things below but they all lead nowhere in the end.
-- can't access the symbol in `readImpl`
type Node (sym :: Symbol) r
= { nodeType :: String
| r
}
TL;DR: The goal is to specify the value of the type
key when I create the specific Node
type and implement the decoding logic that matches the given value against the { "type": "SOME_VALUE" }
JSON object on Node
rather than on all the users of Node
to create things like MyNode