我对镜头的魔力还很陌生,所以我遇到了一些麻烦。
参考: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 monad 一直在使用,所以如果任何“访问器”失败,我会得到一个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")
有没有更优雅的方式来做到这一点?为镜头制作一个 Either-ish monad,结果是什么withFailure
?