我需要一个全局计数器,从0,1,2,3 ......开始 我有点明白,这个“不纯”的代码应该单独实现......我刚开始理解Monad,但不知道如何使用Monad实现这个全局计数器?这可能是理解是否可能的非常有用的示例
答案 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,可用于管理状态。在您的情况下,计数器只是您想要维护的状态。
答案 3 :(得分:2)
虽然State状态良好,但您在计算时无需检查计数器,只是为了增加它,因此Writer monad应该足够了。有关(不太严肃)的介绍,请参阅Learn you a Haskell。