国家Monad的实施

时间:2012-01-31 09:02:06

标签: haskell

我正在研究一个在Haskell中实现状态monad的简单示例。我使用记录语法创建了一个数据类型GlobState。函数incr1,incr2和incr3用于递增各自的记录元素。我写的代码是:

module StateExample where
import Control.Monad.State

data GlobState = GlobState { c1 :: Int, c2:: Int, c3:: Int} deriving (Show)

newGlobState:: GlobState
newGlobState = GlobState { c1=0,c2=0,c3=0 }

--incr1 :: State GlobState ()
incr1 = do
    gets c1
    modify (+1)

--incr2 :: State GlobState ()
incr2 = do
    gets c2
    modify(+1)

incr3 = do
    gets c3
    modify(+1)

main =  do
    let ((),a1) = flip runState newGlobState $ do
        x<- incr1
        y<- incr2 x
        z<- incr1 y
        return z
    print a1

此程序未提供所需的输出。而且我不确定增量函数的签名或者get是否正在做我打算做的事情。请帮忙。

如何更改代码,以便不需要定义不同的增量函数,我只需要生成一个增量函数。我打算这样做:

incr :: String-> State GlobState ()
incr x = do
modify(\g -> g {x =x g + 1})

4 个答案:

答案 0 :(得分:6)

你的类型是正确的,至少。

incr1 :: State GlobState ()
incr1 = modify (\state -> state {c1 = 1 + c1 state})

如果您在modify (+1)工作,State Int ()会没事的,但是我们不是。你似乎认为gets将以下几行集中在一个特定的国家领域 - 但事实并非如此。

incr2incr3需要进行类似的更改。

关于main

  1. 您需要正确缩进代码。您似乎希望print a1成为外部do块的一部分,但不是内部do块的一部分。如果没有缩进,编译器就无法解决这个问题。
  2. 你是(试图)手动线程化状态,但关于State的整点是它的monadic / applicative管道为你做的。
  3. main = do let ((), a1) = flip runState newGlobState $ do incr1
                                                             incr2
                                                             incr1
              print a1
    

答案 1 :(得分:3)

这里的类型是一个问题 - 在这种情况下:

modify :: (GlobState  -> GlobState) -> State GlobState  ()

这是一个问题,因为:

modify (+1) :: (Int -> Int) -> State Int ()

所以你需要用这样的GlobState编写你的函数:

incr1 = modify (\GlobState c1 c2 c3 -> GlobState (c1 + 1) c2 c3)

另外,您可以单独获取和设置状态:

incr1 = do
  (GlobState c1 c2 c3) <- get
  put (GlobState (c1 + 1) c2 c3)

答案 2 :(得分:3)

您可以使用modify包中的fclabels并将其写为

incr1 = modify c1 (+1)
incr2 = modify c2 (+1)
incr3 = modify c3 (+1)

我认为它不会比那更有意。

答案 3 :(得分:2)

这是可行的代码,也许你可以从中构建。

module StateExample where
import Control.Monad.State

data GlobState = GlobState { c1 :: Int, c2:: Int, c3:: Int} deriving (Show)

newGlobState:: GlobState
newGlobState = GlobState { c1=0,c2=0,c3=0 }

incr1 :: State GlobState ()
incr1 = modify (\g -> g {c1 = c1 g +1})

incr2 :: State GlobState ()
incr2 = do
  modify (\g -> g {c2 = c2 g +1})


incr3 :: State GlobState ()
incr3 = do
  modify (\g -> g {c3 = c3 g +1})


main :: IO ()
main =  do
  let a1 = flip execState newGlobState $ do
      incr1
      incr2
      incr1
  print a1