Unable to collect values from a nested JSON using lenses

Viewed 102

Edit

I have managed to get my answer after trying several random permutation. But I still don't understand why the former works, but the latter doesn't:

x ^.. (key "conversations") . values . (key "id") . _String

-- vs

x ^@.. (key "conversations") . values . (imap (\ _ v -> v ^? key "id"))

Original Question

I have a JSON with the following shape:

{
  "conversations":[
    {"id":"abc", ...}, 
    {"id":"abc", ...}, 
    {"id":"abc", ...}, 
    ...
  ]
}

I'm trying to get conversations.*.id using the following expression...

x ^@.. (key "conversations") . values . (imap (\ _ v -> v ^? key "id"))

...which results in the following compiler error:

    • Couldn't match type ‘Maybe’
                     with ‘Const
                             (base-4.13.0.0:Data.Semigroup.Internal.Endo [(Int, Value)])’
      Expected type: IndexedGetting
                       Int
                       (base-4.13.0.0:Data.Semigroup.Internal.Endo [(Int, Value)])
                       BSL.ByteString
                       Value
        Actual type: Indexed
                       Int
                       Value
                       (Const
                          (base-4.13.0.0:Data.Semigroup.Internal.Endo [(Int, Value)]) Value)
                     -> BSL.ByteString -> Maybe BSL.ByteString

values seems to be an "An indexed Traversal into Array elements" and imap seems to be a FunctorWithIndex, so why won't this compose as expected? What am I missing?

PS: I noticed that I have asked a similar question about 2 years ago. Is this question conceptually the same? Am I missing some basic understanding of lenses?

1 Answers

I have managed to get my answer after trying several random permutation. But I still don't understand why the former works, but the latter doesn't:

x ^.. (key "conversations") . values . (key "id") . _String

-- vs

x ^@.. (key "conversations") . values . (imap (\ _ v -> v ^? key "id"))

imap is a mapping function, a variation of fmap that gives access to an index. It is not an optic, and so you can't compose it with other optics in that way. While there is an indexed setter version of imap, imapped, it still wouldn't help, because (^..) requires a fold, and (^@..), an indexed fold. key, on the other hand, sets up a traversal that can be used to retrieve specific properties in the way you intended, because all traversals are folds.

Related