【问题标题】:Why can't I get the increased counter value?为什么我无法获得增加的计数器值?
【发布时间】:2011-06-12 23:16:46
【问题描述】:

我正在尝试在 Haskell 中使用 monads 做一个全局计数器,我想每次使用 monad 计数器时都获得递增的值,但是每次都获得相同的值时我有点卡住了! 代码清单如下:

module CounterMonad where

data Counter a = C (Int -> (Int, a))

--reset the counter
new :: Counter ()
new = C $ \_ -> (0, ())

-- increment the counter:
--inc :: Counter Int
--inc = C $ \n -> (n+1, n)
inc = get >>= \s -> (put (s+1))

-- returning the current value of the counter
get :: Counter Int
get = C $ \n -> (n, n)

--
put x = C $ \n -> (x, x)

--return is nop, >>= is sequential exectuion
instance Monad Counter where
    return r = C $ \n -> (n, r)
    (>>=) (C f) g = C $ \n0 -> let (n1, r1) = f n0
                                   C g' = g r1
                               in g' n1

run :: Counter a -> a
run (C f) = snd (f 0)


tickC  = do
  inc
  c <- get
  return c

当我尝试以run tickC 执行时,它总是返回 1。 我想要的是每次我run tickC 时,它都会返回递增的值,例如 1, ,2, 3,4 .... 我知道那里肯定有一些愚蠢的问题,你们能指出是怎么回事吗?

【问题讨论】:

    标签: haskell monads


    【解决方案1】:

    这是正确的行为。每次调用 run tickC 时,run 函数都会在计数器设置为零的情况下评估操作。本质上,每次调用 run 时,都会得到一个初始化为零的计数器的不同“副本”。

    如果您想让计数器每次都递增,您必须在对run 的同一次调用中执行所有操作。例如,

    tickMany = do
        x <- tickC
        y <- tickC
        z <- tickC
        return [x, y, z]
    
    > run tickMany
    [1, 2, 3]
    

    这适用于所有 monad,包括 IO(忽略“不安全”操作)。由于运行IO 操作的唯一方法是通过main,因此IO monad 将通过每个使用它的函数进行线程化。

    因此,如果您想要一个全局计数器,则该计数器必须由全局使用的 monad 管理(即,由需要访问它的每个函数)。您可以全局使用您的Counter monad,也可以将计数器放在IO monad 中。将这样的状态放入您自己的 monad 似乎是公认的设计实践,但当然,这取决于应用程序,IO 也可以。

    您可能还希望查看Control.Monad.State,它可以让您用更少的输入来定义您的monad。比如:

    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    import Control.Monad.State
    newtype Counter a = Counter (State Int a) deriving (Monad)
    ...
    

    【讨论】:

    • 谢谢 Dietrich~~ 但我不太明白该怎么做:所以如果你想要一个全局计数器,该计数器必须由一个全局使用的 monad 管理(即,由每个函数需要访问它)。您可以在全球范围内使用您的 Counter monad...
    • 所以如果你想让任何函数使用计数器,它必须在Counter monad 中。然后,任何使用该函数的函数也必须在 Counter monad 中,依此类推。
    • 将 Monadic 转换器加入您的学习清单,以了解如何同时管理多个 monad。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-01
    • 2017-02-11
    • 1970-01-01
    • 2011-08-19
    相关资源
    最近更新 更多