2014-01-13 43 views
6

我發現自己經常使用這種模式:在Haskell使用鏡頭修改值

do 
    let oldHeaders = mail ^. headers 
    put $ (headers .~ (insert header value oldHeaders)) mail 

這似乎喜歡那種事Control.Lens應該是能夠做到的,但我想我只是還沒有找到正確的操作員呢。有沒有更好的辦法?另外,還有什麼我應該做的不同,在這個代碼?

回答

10

您可以使用鏈條Lens es和Traversal s直接訪問內部標題值並更新它。

put $ mail & headers . at header ?~ value 

注意(?~)僅僅是\lens value -> lens .~ Just value簡寫。需要Just來向at鏡頭指示我們要插入一個值,如果它不存在。

如果mail在第一行來自國家單子這樣

do 
    mail <- get 
    let oldHeaders = mail ^. headers 
    put $ (headers .~ (insert header value oldHeaders)) mail 

那麼它的簡單的編寫與modify :: MonadState s m => (s -> s) -> m()

modify (headers . at header ?~ value) 

其中,通過與Orjan約翰森的意見建議,可以寫得最勤勉盡責

headers . at header ?= value 
+0

正是我一直在尋找!現在我只需要逐步完成它,所以我確信我理解它。 – Drew

+4

(試圖讓它成爲一個編輯但被拒絕:)記住許多以'〜'結尾的純粹setter運算符都有以'='結尾的monadic狀態更新版本,所以我們可以將'?〜'和modify:標題。在頭?=值' –

+1

難道你只是使用'頭。在標題。遍歷。= value'? –

7

使用鏡頭時,您通常不需要在State monad中明確指定getput。你的情況,你可以使用運營商?=直接更新狀態:

example = do 
    headers . at header ?= value 

您還可以修改任何鏡頭使用%=功能:

example2 = do 
    headers %= insert header value