我用来构成几个过程(带有内存)的惯用法如下:

p1 :: State (Int, String) ()
p1 = do
    (a, b) <- get
    ... do something ...
    put (a', b)

p2 :: State (Int, String) ()
p2 = do
    (a, b) <- get
    ... do something else ...
    put (a, b')

main = do
    ... initializing a0 b0 ...
    print . flip evalState (a0, b0)
          . sequence $ replicate 10 p1 ++ repeat p2

但是,随着状态变量数量的增加,它很快变得比所需的更加冗长:
p1 :: State (Int, String, Bool, Int, String, Bool) ()
p1 = do
    (a, b, c, d, e, f) <- get
    ... do something ...
    put (a, b, c', d, e, f')

p2 :: State (Int, String, Bool, Int, String, Bool) ()
p2 = do
    (a, b, c, d, e, f) <- get
    ... do something ...
    put (a', b', c, d, e, f)

main = do
    print . flip evalState (a0, b0, c0, d0, e0, f0)
          . sequence $ replicate 10 p1 ++ repeat p2

正如我想知道的那样,有没有一种方法可以只更新一些状态变量而不必引用所有未使用的状态变量?我在想类似IORef的东西,但想使用State(实际上有一个stateref包),但是我不确定其他人是否已经使用过一些常见的习惯用法。

最佳答案

这似乎是lenses的工作。特别是 Control.Lens.Tuple 模块以及.=use:

p1 = do
   a <- use _1
   -- do something --
   _1 .= a'

但是,最好给州内的事物起个适当的名字,例如
{-# LANGUAGE TemplateHaskell #-

data Record = MkRecord { _age :: Int
                       , _name :: String
                       , _programmer :: Bool
                       } deriving (Show, Eq)
makeLenses ''Record

这样,您可以为自己的领域取个更好的名字:
p1 = do
   a <- use age
   -- do something --
   age .= a'

请注意,如果您不想使用镜头,这仍然对您有帮助,因为您可以使用记录语法来更新数据:
 p1 = do
      r <- get
      let a = _age r
      --- do something
      put $ r{_age = a'}

关于haskell - 仅更新几个状态变量时如何避免引用所有状态变量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40523355/

10-12 18:52