Haskell var< - 得到什么意思?

时间:2017-12-21 17:58:36

标签: haskell

我遇到过这段代码,但我不知道grid <- get做了什么?我们怎么知道这个网格是我们当前的网格?我们并没有把它作为一个论点。那么我们如何使用它来获取行呢?

data Grid = Grid [Row]
type GridState a = State Grid a

initializeGrid :: GridState ()
initializeGrid = do
        setPositionToColor 2 0 Alive


setPositionToColor :: Int -> Int -> CellState -> GridState ()
setPositionToColor x y color = do
        grid <- get
        let rows = getRows grid
            ...
        put newState

getRows :: Grid -> [Row]
...

2 个答案:

答案 0 :(得分:5)

State monad实际上隐藏了这样一个事实,即每个函数都将状态值作为输入,并在输出中包含(可能已更改)状态。 get实际上只返回隐藏的参数。

如果您在不使用State的情况下编写函数,情况会更清楚。

-- State Grid a == Grid -> (Grid, a)
setPositionToColor :: Int -> Int -> Color -> Grid -> (Grid, ())
                                             ^^^^^^^^^^^^^^^^^^

当您致电setPositionToColor 2 0 Alive时,您实际上并未为网格中的任何特定元素着色,因为尚未涉及网格。您只需返回一个函数,当使用Grid调用 it 时,将生成新修改的Grid

如果没有Monad实例,每次调用setPositionToColor都需要额外的参数,并且它会返回一个新的Grid以传递给下一个调用。您的代码看起来像

let (grid1,_) = setPositionToColor x1 y1 color1 initialGrid
    (grid2,_) = setPositionToColor x2 y2 color2 grid1
    (grid3,_) = setPositionToColor x3 y3 color3 grid2
    (grid4,_) = setPositionToColor x4 y4 color4 grid3
in grid4

所有Monad实例都要注意将中间Grid值从一个函数传递给下一个函数;您需要做的只是提供initialGrid作为runState的参数,它实际上开始调用撰写的State操作。

-- Back to setPositionToColor :: Int -> Int -> Color -> State Grid a
let allFour = setPositionToColor x1 y1 color1 >>= (\() ->
              setPositionToColor x2 y2 color2 >>= (\() ->
              setPositionToColor x3 y3 color3 >>= (\() ->
              setPositionToColor x3 y3 color4)))
in runState allFour initialGrid

或者,因为我们实际上并不关心每次通话返回的()值,

let allFour = setPositionToColor x1 y1 color1 >>
              setPositionToColor x2 y2 color2 >>
              setPositionToColor x3 y3 color3 >>
              setPositionToColor x3 y3 color4
in runState allFour initialGrid

使用do表示法,

let allFour = do
   setPosition x1 y1 color1
   setPosition x2 y2 color2
   setPosition x3 y3 color3
   setPosition x4 y4 color4
in runState allFour initialGrid

答案 1 :(得分:3)

您的网格已“包含”在State monad中。了解您的GridState a是如何定义的?它是State Grid a的别名。它说GridState是一个状态monad,它“携带”Grid类型的状态。

State monad“包含”你的网格的方式也相对简单:你可以look it up,它只是一个以状态为参数的函数。这个monad中的计算只是通过步骤“隧道化”这个参数,但这种情况发生在幕后,对你来说是无形的。编译器将do语法转义为>>=运算符的连续应用程序,对于State monad,此运算符将状态参数“隧道”从一个计算到下一个计算。

get函数是State monad中的monadic操作。它只返回monad中“包含”的状态(你可以look up the function too)。

因此,阅读第grid <- get行的方式是“取出State monad的当前状态,并将其命名为grid ”。