runState和do blocks

时间:2017-05-18 04:09:20

标签: haskell

这是一个更多关于块使用的问题而不是状态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

2 个答案:

答案 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