私は Aeson とレンズ パッケージ (lens-aeson、コア レンズ パッケージから移行) で遊んでおり、それらを連携させるのに苦労しています。
おもちゃの例として、次のタイプがあります。
data Colour = Yellow | Green | Blue
および FromJSON インスタンス:
instance FromJSON Colour where
parseJSON (String s) = return $ case s of
"blue" -> Blue
"green" -> Green
_ -> Yellow
parseJSON _ = mzero
ここまでは順調ですね。
ここで、ネストされた JSON データが入ってきて、これだけを抽出したいとします。
{
"info": {
"colour": "yellow"
},
/* other props */
}
残りは気にしません。この「色」の値だけです。さらに悪いことに、JSON は特に一貫性がないとしましょう。
{ "item": { "colour": "yellow" } }
その他の時間
{ "random": {"item_colour": "yellow"} }
できるだけ簡単に色の値を取得し、理想的には FromJSON インスタンスを使用して色に解析できるようにしたいと考えています。これはおもちゃの例ですが、Color の代わりにデータ型に多数のフィールドなどがある場合があります。
私はレンズ-aesonのものを見始めました、そしてそれは私の希望を上げました。これにより、JSON 構造への非常に簡単なピアリングが可能になります。例:
> "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour"
Just (String "yellow")
> "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour" . _String
Just "yellow"
しかし、 parseJSON 呼び出しでそれを実行して元に戻す方法が見つかりませんJust Yellow
。parseJSON は、適切な型 (おそらく少なくとも内部のもの) を取るという点で近いように見えますが、その後バラバラになります。理想的には、次のいずれかのようなことができます。
> "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour" . _ParseJSON :: Maybe Colour
Just Yellow
> "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour" . _Colour
Just Yellow
私がそれを理解するのに最も近いのは、上記の結果を再エンコードしてからデコードすることです。
> encode $ "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour"
"\"yellow\""
これにより、必要な JSON エンコード データが返されます。より複雑なケースでは、そのデータがオブジェクトまたは配列である場合、decode
通常どおりに実行してより複雑な型を取得できますが、decode は不適切な JSON を好みません。配列またはオブジェクト構文にラップされていないもの。さらに、デコードしてからエンコードするのは非常に面倒で、あまりパフォーマンスが良くないように見えます。
私はレンズと Aeson 全体にかなり慣れていません (そして Haskell については、全体としてモナド/アプリケーションのようなものを理解するようになったので、ゆっくりと進歩しています!)。皆さんはどうやってこれを成し遂げますか?
私の一般的な動機は、JSON データの負荷を処理することですが、実際にはその断片のみを気にするため、JSON のさまざまな場所からそれらの断片を取得する必要があるたびにデータ型を宣言することを避けたいということです。代わりに、気になるビットの型を宣言するだけです。
少し異なる動作をする aeson-lens ではなく、lens-aeson-1 と lens-4.4.0.1 を使用していることに注意してください (回答に関連する可能性があります)。
前もって感謝します!ジェームズ