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

mmvthczy  于 9个月前  发布在  其他
关注(0)|答案(4)|浏览(92)

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

zyfwsgd6

zyfwsgd61#

状态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]
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(不太严重)介绍。

相关问题