私はレンズの魔法に非常に慣れていないので、これに問題があります。
参照: https://www.fpcomplete.com/user/tel/lens-aeson-traversals-prisms
JSON オブジェクトは、次の方法でトラバースできます。
val ^? nth 0 . key "someObject" . key "version" . nth 2
次のような JSON オブジェクトの場合:
"[{\"someObject\": {\"version\": [1, 0, 3]}}]"
Maybe モナドは全体で使用されているため、「アクセサ」が失敗すると、Nothing
.
どのアクセサーが失敗したかがわかるように、失敗も伝播したいと思います。
私が考えることができる唯一の方法は、アクセサーの配列を渡し、それらを順番に適用し、失敗した時点でエラーを返すことです。このようなもの:
import Data.Aeson
import Data.Text
import Data.Vector ((!?))
import qualified Data.HashMap.Strict as HM
data MyAccessor = Nth Int | Key Text
withFailure :: Value -> [MyAccessor] -> Either String Value
withFailure val [] = Right val
withFailure val (x:xs) = case x of
Nth i -> case val of
(Array val') -> case (val' !? i) of
Just e -> withFailure e xs
_ -> Left $ "Could not get index " ++ (show i)
_ -> Left $ "Expected JSON array for index " ++ (show i)
Key k -> case val of
(Object val') -> case (HM.lookup k val') of
Just e -> withFailure e xs
_ -> Left $ "Could not get key " ++ (unpack k)
_ -> Left $ "Expected JSON object for key " ++ (unpack k)
だからこれで:
-- val = [[1,0,3], {"name" : "value"}]
> withFailure val [Nth 1, Key "name", Key "hello"]
Left "Expected JSON object for key hello"
> withFailure val [Nth 1, Key "name"]
Right (String "value")
これを行うよりエレガントな方法はありますか?lens を使用するために、Either-ish モナドを作成すると、次のようになりwithFailure
ます。