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

mmvthczy  于 2023-10-19  发布在  其他
关注(0)|答案(4)|浏览(177)

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

zyfwsgd6

zyfwsgd61#

状态monad给你状态,但只在monad内部。它在函数的重复调用中不是持久的。
如果你想要真正全局的、可变的状态,你可能想做一些像这样的事情:

  1. import Data.IORef
  2. type Counter = Int -> IO Int
  3. makeCounter :: IO Counter
  4. makeCounter = do
  5. r <- newIORef 0
  6. return (\i -> do modifyIORef r (+i)
  7. readIORef r)
  8. testCounter :: Counter -> IO ()
  9. testCounter counter = do
  10. b <- counter 1
  11. c <- counter 1
  12. d <- counter 1
  13. print [b,c,d]
  14. main = do
  15. counter <- makeCounter
  16. testCounter counter
  17. testCounter counter

在这里,makeCounter创建了一个全局可变变量,它在调用之间保持其状态,并破坏纯度。例如,在main函数中,两个相同的testCounter调用会给出不同的结果。

  1. > main
  2. [1,2,3]
  3. [4,5,6]
展开查看全部
6tdlim6h

6tdlim6h2#

您可以使用State monad实现这一点,它将计数器的当前值存储为状态。然后可以使用get获取当前计数器值,并使用modify (+1)递增计数器值。
一个有用的变体是the Supply monad,您可以使用任意序列作为“计数器”,因此要有一个从零开始的普通计数器,只需使用[0..]作为电源。

ehxuflar

ehxuflar3#

你能看到的是状态单子。这是一个通用的monad,可以用来管理状态。在您的情况下,计数器只是您想要维护的一个状态。
http://www.haskell.org/haskellwiki/State_Monad

kxe2p93d

kxe2p93d4#

虽然State很好,但您不需要在计算时检查计数器,只需增加它,因此Writer monad应该足够了。请参阅Learn you a Haskell(不太严重)介绍。

相关问题