Haskell中如何使用optics或lens库获取Map到(k,v)关联对的Fold型optic?
目标类型
Fold (Map k v) (k, v)的实现说明 optics库的实现可行性
optics库原生支持实现该类型的optic,无需自定义遍历逻辑,通过库内置光学元件的标准组合即可完成:
- 引入对应Map模块的光学实例:导入
Data.Map.Strict.Optics(或惰性Map对应的Data.Map.Lazy.Optics),模块中已为Map k v实现itraversed元件,其类型为IndexedTraversal k (Map k v) v——该元件的索引值对应当前Map条目的键,遍历值对应当前键存储的值。 - 通过
withIndex组合子完成类型转换:该组合子的作用是将带索引的Indexed光学元件转换为普通光学元件,遍历输出的每个元素会被包装为(索引, 遍历值)的二元组。最终组合得到的元件类型完全匹配需求:kvFold :: Fold (Map k v) (k, v) kvFold = withIndex itraversed - 类型匹配原理:IndexedTraversal本身是可以无副作用遍历所有Map条目的遍历器,天然满足Fold的只读遍历、收集元素的能力要求;经
withIndex转换后,元件不再携带索引语义,输出元素变为键值对(k, v),类型与需求完全一致。
lens库的对应实现方式
如果在lens生态下开发,可通过完全对等的组合逻辑得到相同类型的元件:
- 导入
Control.Lens.At与Control.Lens.Indexed模块,lens库同样为Map k v定义了语义完全一致的itraversedIndexedTraversal,索引为Map条目键,遍历值为条目存储内容。 - 搭配
lens库内置的withIndex组合子,即可得到目标类型的Fold:kvFold :: Fold (Map k v) (k, v) kvFold = withIndex itraversed - 补充说明:不推荐直接以
Map.toList为源构造Fold,这类方式直接将Map整体转换为列表再做折叠,丢失了optic的可组合性优势,优先使用上述基于索引遍历的组合方案。
内容的提问来源于stack exchange,提问作者Nikita Volkov
相关产品推荐
相关产品推荐

