The easiest way to use JSON as dynamically typed data in Haskell is with the lens[1] and lens-aeson[2] packages. The type signatures those use are astounding, and not trivial to understand.
But the code that results is very simple while remaining strongly typed.
It ends up being not that different in style from something like hpricot in ruby.
The keys of the hashmap are Text and the leaves are "Value" which contain more JSON
here are different well-formed json values that both resolve to the same type, A.Object (either you get a parse error String for not-well-formed json, or an A.Object)
>>> A.eitherDecode "{ \"name\": \"Joe\", \"age\": 12 }" :: Either String A.Object
Right (fromList [("age",Number 12.0),("name",String "Joe")])
>>> A.eitherDecode "{ \"name\": \"Joe\", \"age\": {\"foo\": \"12\"} }" :: Either String A.Object
Right (fromList [("age",Object (fromList [("foo",String "12")])),("name",String "Joe")])
Then you can access values in the HashMap by key just like a hashmap in any other language.
Or, as noted by chowells, you can use lens-aeson which can be thought of as a DSL to perform queries in a dynamic fashion:
retrieve value of "foo" in "age"
>>> s = "{ \"name\": \"Joe\", \"age\": {\"foo\": \"12\"} }" :: String
>>> s ^? key "age" . key "foo"
Just (String "12")