使用嵌套状态转换器修改可移动镜头

Modify a traversable lens using a nested state transformer

我有一个包含多个 _objectsOuterState 对象,应该使用 nestedAction 对其进行修改,这也需要访问 OuterState 对象。因此,nestedAction 是一个嵌套状态转换器,每个 InnerStateObject 是 运行,如本例所示:

{-# LANGUAGE TemplateHaskell #-}

module Main where

import Control.Lens ((+=), makeLenses)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.State.Lazy
       (StateT, evalStateT, execStateT, get)
import Control.Monad.Trans.Class (lift)

data OuterState = OuterState
  { _objects :: [InnerStateObject]
  , _count :: Int
  } deriving (Show)

data InnerStateObject = InnerStateObject
  { _value :: Int
  } deriving (Show)

makeLenses ''OuterState

makeLenses ''InnerStateObject

startNestedAction :: StateT OuterState IO ()
startNestedAction = do
  get >>= liftIO . putStrLn . ("before: " ++) . show
  objects . traverse <~% execStateT nestedAction
  get >>= liftIO . putStrLn . ("after: " ++) . show

nestedAction :: StateT InnerStateObject (StateT OuterState IO) ()
nestedAction = do
  value += 10
  lift $ count += 100

main :: IO ()
main =
  evalStateT
    startNestedAction
    OuterState {_count = 0, _objects = map InnerStateObject [0 .. 2]}

本例中缺少 <~% 的定义。优先级为infixr 2 <~%。它应该将 objects . traverse 的每个值传递给 execStateT nestedAction 并将结果分配给 objects . traverse.

如何实施 <~%?它的类型是什么?


依赖项: lts-9.3

use objects >>= traverse (execStateT nestedAction) >>= assign objects

object . traverse 粒度太粗,无法在 objects 字段的遍历期间优雅地表达 count 字段的更新(通过 nestedAction 隐式)。这基本上就是镜头库没有运算符 (<~%) :: MonadState s m => ATraversal' s a -> (a -> m a) -> m () 的原因:如果它的第二个参数修改了第一个参数中遍历的目标状态部分,它就不会表现良好。