5

私の目標は、jsonファイルの名前を取り、残りの引数をそのjsonファイルをナビゲートし、ナビゲートされた値を出力するパスとして解釈するプログラムをHaskellで作成することです。問題は、JSONに複数の値型を含めることができるため、Haskellの型システムに必要なものを理解させる方法がわかりません。これが私が正しく実装できない「ナビゲート」機能を備えたHaskellコードです:

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))

参考までに、同じプログラムが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)

プログラムは次のように実行されます。

$ cat data.json
{"foo" : [[1, 2, 3, {"bar" : "barf"}]]} 
$ python showjson.py data.json foo 0 3 bar
barf
4

1 に答える 1

4

のコンストラクターでパターンマッチングを行うだけで、A.Value処理しているJSONオブジェクトの種類を把握できます。

import qualified Data.HashMap.Strict as M
import qualified Data.Vector as V
import qualified Data.Text as T

-- ... rest of the code more or less as before ...

navigate :: A.Value -> [String] -> BSL.ByteString
navigate value        []       = A.encode value
navigate (A.Array vs) (x : xs) = navigate (vs V.! read   x) xs
navigate (A.Object o) (x : xs) = navigate (o  M.! T.pack x) xs

の定義A.Valueは次のとおりであることに注意してください。

data Value
  = Object !(HashMap Text Value)
  | Array  !(Vector Value)
  | ...  -- other constructors

したがって、のコードは、ベクトルとハッシュマップnavigateのルックアップ関数(どちらの場合も呼び出されます)を利用しています。!この関数readは、必要に応じてコマンドライン引数を数値として解釈するために使用されます(そうでない場合はひどく失敗します)がT.pack、文字列をタイプの値として再解釈しますText

于 2012-11-06T12:53:14.047 に答える