如何使用镜头从多层嵌套中获取钥匙?
请考虑以下类型
data Outer = Outer { _outerMap :: Map String Inner }
data Inner = Inner { _innerMap :: Map Char Int }
makeLenses ''Outer
makeLenses ''Inner
并采用以下示例值
example :: Outer
example = Outer $ Map.fromList
[ ("A", Inner $ Map.fromList [ ('a', 1), ('b', 2), ('c', 3) ])
, ("B", Inner $ Map.fromList [ ('a', 4), ('b', 6), ('c', 8) ])
, ("C", Inner $ Map.fromList [ ('a', 5), ('b', 7), ('c', 9) ])
]
使用透镜,我可以将example
展平为[Int]
并按如下所示过滤奇数:
>>> example^..outerMap.folded.innerMap.folded.filtered odd
[1,3,5,7,9]
我可以使用内键注释值,如下所示:
>>> example^@..outerMap.folded.innerMap.ifolded.filtered odd
[('a',1),('c',3),('a',5),('b',7),('c',9)]
但是我该如何使用镜头同时使用外键和内键注释值,以获得以下结果?
>>> _whatHere example
[(("A",'a'),1),(("A",'c'),3),(("C",'a'),5),(("C",'b'),7),(("C",'c'),9)]
以下尝试仍仅返回内部键:
>>> example^@..outerMap.ifolded.innerMap.ifolded.filtered odd
[('a',1),('c',3),('a',5),('b',7),('c',9)]
并且以下尝试未进行类型检查
>>> example^..outerMap.ifolded.withIndex.alongside id (innerMap.ifolded.filtered odd.withIndex)
error:
• No instance for (Applicative
(Control.Lens.Internal.Getter.AlongsideRight
(Const (Data.Monoid.Endo [([Char], (Char, Int))])) [Char]))
没有镜头的实现可能看起来像这样:
nolens :: Outer -> [((String, Char), Int)]
nolens =
filter (odd . snd)
. foldMap (\(k, i) -> (map (first (k, )) . Map.toList . _innerMap) i)
. Map.toList
. _outerMap
答案 0 :(得分:2)
使用(<.>)
。就像(.)
一样,除了它保留左右两边的索引。 (.)
本身(及其别名(.>)
)仅保留RHS的索引,除非RHS本身保留索引,在这种情况下,索引来自LHS。助记符是箭头指向您要保存的索引。
>>> example^@..outerMap.ifolded<.>innerMap.ifolded.filtered odd
[(("A",'a'),1),(("A",'c'),3),(("C",'a'),5),(("C",'b'),7),(("C",'c'),9)]