1. 5
  1.  

  2. 4

    I don’t think introducing lenses, prefacing the post with language extensions, and using TH for a multiline string amounts to “easy json parsing.” Here’s a stub using only base and aeson to implement an off-brand jq in 35 lines.

    $ cat json | stack run ?people _0 ?hobbies _0 ?name
    "bridge"
    

    import Data.Char (isDigit)
    import Data.Foldable (toList)
    import Data.String (fromString)
    import System.Environment (getArgs)
    
    import Data.Aeson
    import Data.Aeson.Types
    import Data.ByteString.Lazy as BS (ByteString, interact)
    
    main :: IO ()
    main = do
        args <- getArgs
        BS.interact (either error encode . decodeAndSearch args)
    
    decodeAndSearch :: [String] -> ByteString -> Either String Value
    decodeAndSearch args bytes = do
        val <- eitherDecode bytes
        parseEither (search args) val
    
    search :: [String] -> Value -> Parser Value
    search [] val = return val
    search (arg:args) val =
        case arg of
            '_':ds | all isDigit ds ->
                flip (withArray "Arr") val $ \arr -> do
                    let idx = read ds
                        xs = toList arr
                    if idx < length xs
                    then search args (xs !! idx)
                    else fail $ "Index out of bounds for array: " ++ show (idx, length xs)
            '?':key ->
                flip (withObject "Obj") val $ \obj -> do
                    fld <- parseField obj (fromString key)
                    search args fld
            _ -> fail $ "Use !<digits> to index arrays or ?<key> to lookup in an object. Saw: " ++ show arg
    
    1. 2

      jq is off-brand lens!