2

我还没有完全理解镜头。

applicationState = (
    'a',
    'b',
    (   M.fromList $ zip [1..3]  [11,22,33],
        M.fromList $ zip [4,5,6] [44,55,66],
        M.fromList $ zip [7,8,9] [M.fromList $ zip [2,3,4] ["77","777","7777"],
        M.fromList $ zip [2,3,4] ["88","888","8888"],
        M.fromList $ zip [2,3,4] ["99","999","9999"]] )
    )

有没有更惯用的镜头方式来做到这一点:

λ> view (_3 . _3 . at 9) applicationState >>= view (at 4) >>= return . ('9':)
Just "99999"
4

1 回答 1

2

您可以使用traverse :: Traversal (Maybe a) (Maybe b) a b然后使用preview

preview (_3 . _3 . at 9 . traverse . at 4 . traverse . to ('9':)) applicationState

因为ix i = at i . traverse,这也可以写成:

preview (_3 . _3 . ix 9 . ix 4 . to ('9':)) applicationState

你也可以这样修改,但是如果任何一个at' 失败,什么都不会改变(你不能使用 a 在你的地图中插入新元素Traversal)。


另一种方法是使用non :: a -> Lens' (Maybe a) a. 这仅在第一个映射(由 lens 访问_3._3)从不包含空映射作为值且第二个映射从不包含空字符串作为值的情况下才有效。因此以下值对于 applicationState 无效:

('a', 'b', 
  ( M.fromList $ zip [1..3] [11,22,33]
  , M.fromList $ zip [4,5,6] [44,55,66]
  , M.fromList $ zip [7..9] [M.empty] -- No value of this map may be the empty map
  )
)

使用non,您的示例可以写为:

view (_3 . _3 . at 9 . non M.empty . at 4 . non "" . to ('9':)) applicationState

这也允许通过设置插入新条目(如果您设置并且键 4 或 9 尚不存在,它们将被创建)和删除条目(如果您设置为值“”,键 4 将被删除,并且如果删除该键后映射为空,则键 9 也将被删除)。

于 2014-07-09T12:00:10.753 回答