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)
你喜欢像镜头一样
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)
这将允许您获取(使用preview或toListOf)并设置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)
所以经常最好避免使用这些假象来防止意外事故.