2017-05-18 66 views
0

這是一個比狀態monad更多關於do block用法的問題。在下面的代碼中,我們可以直接使用do塊直接使用runState,但只能使用翻轉來顛倒參數的順序,以便首先給出要使用的初始狀態。runState和do blocks

爲什麼人們必須使用flip構造,換句話說,如何將do塊作爲runState的第一個參數?

module Main where 

import qualified Data.Map as Map 
import Control.Monad.State 

type MapS = Map.Map Int String 

-- Add an item (key value pair) to map 
addItemToMap :: Int -> String -> State MapS() 
addItemToMap x s = modify $ Map.insert x s 

main :: IO() 
main = do 
    let r = flip runState Map.empty $ do 
     addItemToMap 101 "one hundred and one" 
     addItemToMap 1001 "one thousand and one" 
    print r 
+0

'flip' *是*如何切換參數順序。 –

+0

但我的問題是爲什麼你不能在這種情況下以正常順序調用runState參數,而不是關於flip的操作。我不知道如何以這種方式調用do。 – andro

回答

3

如何將do塊作爲runState的第一個參數?

您可以用括號括起來做塊,你將與其他表達式做:

let r = runState (do 
     addItemToMap 101 "one hundred and one" 
     addItemToMap 1001 "one thousand and one") Map.empty 

這是一個有點尷尬,不過,這也就是爲什麼flip往往與在runState使用你描述的方式。

1

runState的參數順序基於的假設是,起始狀態(第二個參數)將高於該動作(第一個參數)更頻繁地變化很可能選擇的。如果您想翻轉參數順序,除了使用flip(或其他等效方法)之外,沒有別的。這正是翻轉的目的。

如果您願意,可以給flip runState一個名稱,以便重用。例如,lens has &~爲(相當於)flip execState