在Haskell中带镜头的惯用风格

时间:2014-07-09 09:23:17

标签: haskell lens

我还没有完全了解镜头。

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"

1 个答案:

答案 0 :(得分: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中的任何一个失败,则不会更改任何内容(您无法使用Traversal在地图中插入新元素)。


另一种方法是使用non :: a -> Lens' (Maybe a) a。仅当第一个地图(由镜头_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尚未存在,它们将被创建)并删除条目(如果您设置为值"&# 34;,键4将被移除,如果在移除该键后地图为空,则键9也将被移除)。