Haskell 如何使用Monad实现全局计数器?
我需要一个全局计数器,从0,1,2,3。。。。。Haskell 如何使用Monad实现全局计数器?,haskell,monads,Haskell,Monads,我需要一个全局计数器,从0,1,2,3。。。。。 我有点理解这个“不纯”的代码应该单独执行。。。我刚刚开始理解Monad,但不知道如何使用Monad实现这个全局计数器?这可能是一个非常有用的例子,有助于理解是否可能您可以研究的是状态单子。这是一个通用的monad,可用于管理状态。在您的情况下,计数器只是您想要维护的状态 虽然状态良好,但在计算时不需要检查计数器,只需增加计数器即可,这样就足够了。请参阅以获得(不太严肃的)介绍。State monad提供状态,但仅在monad内部提供。它不会在函数
我有点理解这个“不纯”的代码应该单独执行。。。我刚刚开始理解Monad,但不知道如何使用Monad实现这个全局计数器?这可能是一个非常有用的例子,有助于理解是否可能您可以研究的是状态单子。这是一个通用的monad,可用于管理状态。在您的情况下,计数器只是您想要维护的状态
虽然状态良好,但在计算时不需要检查计数器,只需增加计数器即可,这样就足够了。请参阅以获得(不太严肃的)介绍。State 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
您可以使用
State
monad实现这一点,它将计数器的当前值存储为状态。然后,您可以使用get
获取当前计数器值,并使用modify(+1)
将其递增
其中一个有用的变化是,您可以使用任意序列作为“计数器”,因此要有一个从零开始的普通计数器,只需使用
[0..]
作为供应。我不确定使用编写器是否足够-如果您想在计算过程中了解当前计数,您无法从编写器获取它(仅写状态)它必须是一个状态单子。@stephen tetley这个问题不清楚在计算过程中是否需要计数器值。但是,如果您只需要计数器的最终结果,编写器
更“安全”,更易于使用。正如Ankur所说,这基本上是一个状态单子。Monad实例的实现--return
和bind(>>=)
-将与State相同,但是您需要的更新操作不如State Monad的put
(put
可以以任意方式更改状态)。我建议一个好的接口是next
,它增加计数并返回新计数。保留一个只查询计数而不更新计数的get
操作也很好。签出。要获得计数器,只需使用[0..]
作为补充。@哈马尔您的评论应该是答案,并且应该被接受。为什么您要在计数器上签名而不是简单地签名IO Int
?
> main
[1,2,3]
[4,5,6]