Jestem nowy w magii soczewek, więc mam z tym problem.Aeson i soczewki z obsługą błędów
W odniesieniu do: https://www.fpcomplete.com/user/tel/lens-aeson-traversals-prisms
obiekt JSON może być wykonywany w następujący sposób:
val ^? nth 0 . key "someObject" . key "version" . nth 2
dla obiektu JSON, który przypomina:
"[{\"someObject\": {\"version\": [1, 0, 3]}}]"
Może monada jest używany w całym, więc jeśli jakikolwiek "accessor" nie powiedzie się, otrzymuję Nothing
.
Chciałbym również propagować awarię, aby wiedzieć, co nie udało się uzyskać.
Jedyny sposób, w jaki mogę to zrobić, to przekazanie tablicy akcesorów, zastosowanie ich kolejno i zwrócenie błędu w dowolnym momencie, który się nie powiódł. Coś takiego:
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)
Więc z tego:
-- 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")
Czy jest bardziej elegancki sposób to zrobić? Tworzenie monady na obiektyw do użycia, które skutkuje tym, czym jest withFailure
?