haskell - Parsing JSON into RoseTree (recursive parsing) -
i struggling function take string json input , return rosetree structure output.
my code follows:
import qualified data.aeson json import qualified data.text t import qualified data.aeson.types @ import control.applicative import qualified data.bytestring.char8 bs import data.attoparsec.bytestring.char8 data rosetree = empty | rosetree [rosetree a] deriving (show) instance (show a) => json.tojson (rosetree a) tojson (rosetree n cs) = json.object [t.pack "value" json..= show n , t.pack "children" json..= json.tojson cs] instance (show a, json.fromjson a) => json.fromjson (rosetree a) parsejson (json.object o) = rosetree <$> o json..: t.pack "value" <*> o json..: t.pack "children" parserosetreefromjson :: (show a, json.fromjson a) => string -> (rosetree a) parserosetreefromjson json = let bs = bs.pack json in case parse json.json bs of (done rest r) -> case at.parsemaybe json.parsejson r of (just x) -> x nothing -> empty _ -> empty it converts rosetree structure json fine. example, when run json.encode $ json.tojson $ rosetree 1 [], returns "{\"children\":[],\"value\":\"1\"}", running json.encode $ json.tojson $ rosetree 1 [rosetree 2 []] returns "{\"children\":[{\"children\":[],\"value\":\"2\"}],\"value\":\"1\"}".
but when try supply json have got on previous step parser, returns empty:
*main> parserosetreefromjson "{\"children\":[],\"value\":1}" empty *main> parserosetreefromjson "{\"children\":[{\"children\":[],\"value\":\"2\"}],\"value\":\"1\"}" empty similarly,
*main> json.decode $ bls.pack "{\"children\":[{\"children\":[],\"value\":\"2\"}],\"value\":\"1\"}" nothing i suspect parser incorrectly defined. cannot tell wrong. approach using correct 1 approach recursive parsing? right way recursively?
weird ghci typing rules strike again! works expected if add type annotations:
ghci> :set -xoverloadedstrings ghci> json.decode "{\"children\":[],\"value\":1}" :: maybe (rosetree int) (rosetree 1 []) without knowing type trying parse (it sees fromjson => maybe a), ghci defaults a ~ (). can try out testing fromjson () instance out , noticing succeeds!
ghci> json.decode "[]" () couple side notes on code if project (and not fun , learning):
- i encourage check out
overloadedstrings(you can drop uses oft.packcode since string literals infer whether should have typestring, lazy/stricttext, lazy/strictbytestringetc.) - you can use
derivegeneric,deriveanyclassjson parsing free (although concede behavior slightly different have)
with suggestions, here rewrite of code:
{-# language overloadedstrings, derivegeneric, deriveanyclass #-} import qualified data.aeson json import qualified data.bytestring.lazy.char8 bs import ghc.generics (generic) import data.maybe (frommaybe) data rosetree = rosetree { value :: a, children :: [rosetree a] } deriving (show, generic, json.fromjson, json.tojson) note decode data.aeson (almost) parserosetreefromjson does...
ghci> :set -xoverloadedstrings ghci> json.encode (rosetree 1 []) "{\"children\":[],\"value\":1}" ghci> json.encode (rosetree 1 [rosetree 2 []]) "{\"children\":[{\"children\":[],\"value\":2}],\"value\":1}" ghci> json.decode "{\"children\":[],\"value\":1}" :: maybe (rosetree int) (rosetree {value = 1, children = []}) ghci> json.decode "{\"children\":[{\"children\":[],\"value\":2}],\"value\":1}" :: maybe (rosetree int) (rosetree {value = 1, children = [rosetree {value = 2, children = []}]})
Comments
Post a Comment