这是一个更多关于块使用的问题而不是状态monad。在下面的代码中,我们可以直接在runState中使用do块,但只能使用flip来反转参数的顺序,以便首先给出要使用的初始状态。
为什么必须使用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 :(得分:3)
如何将do块作为runState的第一个参数?
您可以将do-block括在括号中,就像使用其他表达式一样:
let r = runState (do
addItemToMap 101 "one hundred and one"
addItemToMap 1001 "one thousand and one") Map.empty
这有点尴尬,这就是flip
经常与runState
一起使用的原因。
答案 1 :(得分:1)
runState
的参数顺序可能是基于假设起始状态(第二个参数)比动作(第一个参数)更频繁地变化而选择的。如果你想翻转参数顺序,除了使用flip
(或其他一些等效方法)之外别无其他。这正是翻转的目的。
如果您愿意,可以给flip runState
一个名称,以便更容易重复使用。例如,lens has &~
表示(相当于)flip execState
。