如何使用Monad实现全局计数器?

时间:2011-06-10 05:15:28

标签: haskell monads

我需要一个全局计数器,从0,1,2,3 ......开始 我有点明白,这个“不纯”的代码应该单独实现......我刚开始理解Monad,但不知道如何使用Monad实现这个全局计数器?这可能是理解是否可能的非常有用的示例

4 个答案:

答案 0 :(得分:8)

状态monad给你状态,但只在monad中。它在函数的重复调用中不是持久的。

如果你想要真正全球化,可变的状态,你可能想做类似的事情:

  import Data.IORef

  type Counter = Int -> IO Int

  makeCounter :: IO Counter
  makeCounter = do
      r <- newIORef 0
      return (\i -> do modifyIORef r (+i)
                       readIORef r)

  testCounter :: Counter -> IO ()
  testCounter counter = do
      b <- counter 1
      c <- counter 1
      d <- counter 1
      print [b,c,d]

  main = do
      counter <- makeCounter
      testCounter counter
      testCounter counter

这里'makeCounter'创建一个全局的,可变的变量,它保持调用状态并破坏纯度。例如,在main函数中,对'testCounter'的两次相同调用会产生不同的结果。

> main
[1,2,3]
[4,5,6]

答案 1 :(得分:6)

您可以使用State monad来实现此功能,该monad将计数器的当前值存储为状态。然后,您可以使用get获取当前的计数器值,并使用modify (+1)来增加它。

其中一个有用的变体是the Supply monad,您可以使用任意序列作为“计数器”,因此要从零开始使用普通计数器,只需使用[0..]作为供应。 / p>

答案 2 :(得分:5)

你可以看到的是状态monad。这是一个通用monad,可用于管理状态。在您的情况下,计数器只是您想要维护的状态。

http://www.haskell.org/haskellwiki/State_Monad

答案 3 :(得分:2)

虽然State状态良好,但您在计算时无需检查计数器,只是为了增加它,因此Writer monad应该足够了。有关(不太严肃)的介绍,请参阅Learn you a Haskell