2017-06-13 77 views
0

下面是an answer regarding memoization的代碼,顯示了狀態monad中使用的memoization函數,其中狀態用傳遞的函數的結果更新,如果密鑰尚未在地圖中。有條件地更新State monad地圖的方法

type MyMemo a b = State (Map.Map a b) b 

myMemo :: Ord a => (a -> MyMemo a b) -> a -> MyMemo a b 
myMemo f x = do 
    map <- get 
    case Map.lookup x map of 
    Just y -> return y 
    Nothing -> do 
     y <- f x 
     modify $ \map' -> Map.insert x y map' 
     return y 

它看起來並不像慣用的Haskell:它感覺非常必要,並不是每一行都有這麼多的東西。

有沒有辦法做到上述,但在一個更簡潔/功能的風格?我瀏覽了http://hackage.haskell.org/package/transformers-0.5.4.0/docs/Control-Monad-Trans-State-Lazy.html#v:state的功能,但沒有什麼真正的幫助。

回答

3

我認爲你的代碼是功能風格的,但是你可以簡化它。

myMemo f x = maybe work return =<< gets (Map.lookup x) 
    where 
    work = do 
     y <- f x 
     modify $ Map.insert x y 
     return y 
+0

爲什麼='的'<<代替'>> ='替代(與參數相反)? –

+0

@MichalCharemza,我通常更喜歡= = <<' to '>> =,它更像應用程序。例如。 '($)::(a→b)→a→b'類似於(= <<) :: (a -> m b)→m a→m b'。然後,數據始終從右向左流動,而不是根據是否是單向切換方向。 – luqui

+0

@MichalCharemza我認爲這取決於代碼風格。我選擇最方便的操作員。在這種情況下,這兩個操作員都很方便,所以我會用另一個規則,luqui寫道。 – freestyle

0

這是一個使用mapState,以及>>=https://stackoverflow.com/a/44515364/1319998maybe替代,即避免了所有該做的記號

myMemo f x = gets (Map.lookup x) >>= maybe y' return 
    where 
    y' = mapState (\(y, map) -> (y, Map.insert x y map)) $ f x 
0

這是擴展了https://stackoverflow.com/a/44515364/1319998,使用更>>=避免替代所有的符號

myMemo :: Ord a => (a -> MyMemo a b) -> a -> MyMemo a b 
myMemo f x = gets (Map.lookup x) >>= maybe y' return 
    where 
    y' = f x >>= \y -> state $ \map -> (y, Map.insert x y map)