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 of t.pack code since string literals infer whether should have type string, lazy/strict text, lazy/strict bytestring etc.)
  • you can use derivegeneric , deriveanyclass json 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

Popular posts from this blog

What is happening when Matlab is starting a "parallel pool"? -

angular - DownloadURL return null in below code -

php - Cannot override Laravel Spark authentication with own implementation -