10

我正在努力适应lensHaskell 的库,并发现自己在一些简单的问题上苦苦挣扎。例如,假设(为方便起见)at_1具有以下类型(至少我是这样理解它们的):

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

_1 :: Lens' (a, b) a

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

maybeFst :: Ord k => k -> Lens' (Map k (a, b)) (Maybe a)
4

1 回答 1

8

你想要一个像这样的镜头

Lens' (Maybe (a, b)) (Maybe a)

但这不太可能,Lens因为放回也会Nothing影响到b。它可以是一个Getter

getA :: Getter (Maybe (a, b)) (Maybe a)
getA = to (fmap fst)

但是当你创作它时,你也会得到一个Getter,而不是一个完整的Lens

maybeFst :: Ord k => k -> Getter (Map k (a, b)) (Maybe a)
maybeFst k = at k . getA

可能比那更好的是使用 aTraversal代替

maybeFstT :: Ord k => k -> Traversal' (Map k (a, b)) a
maybeFstT k = at k . _Just . _1

这将允许您在地图中的值处获取(使用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)

但请注意,它有一些不太Lens相似的行为。

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

>>> Nothing & getA 0 .~ Just 1
Just (1,0)

所以通常最好避免使用这些伪透镜以防止发生意外。

于 2014-03-12T20:49:34.163 回答