How do I avoid referring to all state variables when updating only a few?

后端 未结 3 718
名媛妹妹
名媛妹妹 2021-01-07 20:04

An idiom I use for composing a couple of procedures (with memory) is as follows:

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


        
3条回答
  •  有刺的猬
    2021-01-07 20:35

    lens's zoom combinator lifts a computation in a State monad into a computation that runs in a "larger" State monad.

    zoom :: Lens' s t -> State t a -> State s a
    

    So, given a "big" state:

    data Big = Big {
        _big1 :: Medium,
        _big2 :: Medium
    }
    data Medium = Medium {
        _medium1 :: Small,
        _medium2 :: Small
    }
    data Small = Small { _small :: Int }
    
    makeLenses ''Big
    makeLenses ''Medium
    makeLenses ''Small
    

    you can "zoom in" on a part of the state:

    incr :: State Int ()
    incr = id += 1
    
    incrSmall :: State Big ()
    incrSmall = zoom (big2.medium1.small) incr
    

    Of course, this'll work on big tuples as well as records, using lens's built-in tuple field accessors.

    zoom's real type signature is more general than the simple one I quoted above. It uses MonadState constraints to work under a monad transformer stack, rather than in State specifically.

提交回复
热议问题