如何组合镜片和仿函数?

wen*_*wen 11 haskell lenses haskell-lens

我正在尝试习惯lensHaskell 的库,发现自己在一些简单的问题上苦苦挣扎.例如,让我们说(为了方便起见)at并且_1具有以下类型(这至少是我理解它们的方式):

at :: Ord k => k -> Lens' (Map k v) (Maybe v)

_1 :: Lens' (a, b) a
Run Code Online (Sandbox Code Playgroud)

如何将这些镜头组合成以下类型的镜头:

maybeFst :: Ord k => k -> Lens' (Map k (a, b)) (Maybe a)
Run Code Online (Sandbox Code Playgroud)

J. *_*son 9

你喜欢像镜头一样

Lens' (Maybe (a, b)) (Maybe a)
Run Code Online (Sandbox Code Playgroud)

但这不可能是一个Lens因为挫折Nothing影响了b.它可以是一个Getter

getA :: Getter (Maybe (a, b)) (Maybe a)
getA = to (fmap fst)
Run Code Online (Sandbox Code Playgroud)

但是当你构成它时,你只会结束一个Getter,而不是一个完整的Lens

maybeFst :: Ord k => k -> Getter (Map k (a, b)) (Maybe a)
maybeFst k = at k . getA
Run Code Online (Sandbox Code Playgroud)

可能更好的是用一个Traversal代替

maybeFstT :: Ord k => k -> Traversal' (Map k (a, b)) a
maybeFstT k = at k . _Just . _1
Run Code Online (Sandbox Code Playgroud)

这将允许您获取(使用previewtoListOf)并设置fst地图中值的值,但您将无法在地图中修改其存在:如果该值不存在,则无法添加它,如果它确实存在你无法删除它.


最后,我们可以陪审一个Lens具有适当类型的假货,但我们必须给它一个默认值b

getA :: b -> Lens' (Maybe (a, b)) (Maybe a)
getA b inj Nothing       = (\x -> (,b) <$> x) <$> inj Nothing
getA _ inj (Just (a, b)) = (\x -> (,b) <$> x) <$> inj (Just a)
Run Code Online (Sandbox Code Playgroud)

但请注意它有一些不太Lens喜欢的行为.

>>> Just (1, 2) & getA 0 .~ Nothing & preview (_Just . _2)
Nothing

>>> Nothing & getA 0 .~ Just 1
Just (1,0)
Run Code Online (Sandbox Code Playgroud)

所以经常最好避免使用这些假象来防止意外事故.

  • 谢谢,我现在看到我要求的类型永远不会是一个镜头!:) (2认同)