2014-03-12 28 views
11

我想要習慣於Haskell的lens庫,並發現自己在一些簡單的問題上掙扎。舉例來說,假設(爲了方便),其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) 

回答

9

你希望像

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 

可能會更好比是使用Traversal而不是

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) 

所以最好避免這些假牙來防止事故發生。

+2

謝謝,我現在看到我所要求的類型永遠不可能是鏡頭! :) – wen

+1

最後一點,如果我們有'Iso'(a,b)a'(這顯然是不可能的,那麼我們可以使用'映射ourIso :: Iso'(Maybe(a,b)) )'代替'getA'。也就是說,嘗試'fl(a,b)=(b,a)'用'flipP = iso fl fl',然後'maybeFlip k = at k。映射flipP :: Ord k => k - > Lens'(Map k(a,b))(Maybe(b,a))'。 –

+0

只是一個小小的澄清:你的第一個例子不能成爲鏡頭的原因是你不能發明一個'b'放入'Nothing'時試圖放入'Just a',反過來就好了,這是我的嘗試:'不可能:: Lens'(Maybe(a,b))(也許a);' '不可能k(Just(a,b))= fmap(,b)<$> k(Just a);' '不可能k nothing = fmap(,undefined)<$> k Nothing'。 '不可能k沒有=沒有<$ k沒什麼',但是這不符合鏡頭法則。 – Hjulle