My goal is to write a program in Haskell that takes the name of a json file and interprets the rest of the arguments as a path to navigate that json file by and print the value navigated to. The problem is because JSON can contain multiple value types, I don't know how to make Haskell's type system understand what I want. Here is the Haskell code with the "navigate" function I'm not able to implement correctly:
import qualified Data.Aeson as A
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as BSL
import Data.List
import Data.Maybe
import System.Environment
parse :: String -> A.Value
parse = fromJust . A.decode . BSL.pack
isInteger xs = case reads xs :: [(Integer, String)] of
[(_, "")] -> True
_ -> False
navigate :: A.Value -> String -> String
navigate value [] = value
navigate value [x:xs]
| isInteger x = ??? -- value is an array, get the xth element of it.
| otherwise = ??? -- value is an map, x is a key in it.
main :: IO ()
main = do
[filename:path] <- getArgs
contents <- readFile filename
let d = parse contents
putStrLn (show (navigate d path))
For reference, here is how the same program would have been written in Python:
from json import load
from sys import argv
def navigate(obj, path):
if not path:
return obj
head, tail = path[0], path[1:]
return navigate(obj[int(head) if head.isdigit() else head], tail)
if __name__ == '__main__':
fname, path = argv[1], argv[2:]
obj = load(open(fname))
print navigate(obj, path)
The program would be run like this:
$ cat data.json
{"foo" : [[1, 2, 3, {"bar" : "barf"}]]}
$ python showjson.py data.json foo 0 3 bar
barf