Julian Stecklina
Julian Stecklina

Reputation: 1281

How to update parts of the state in a State monad?

I have a type that I'd like to use as part of a state monad:

{-# LANGUAGE TemplateHaskell #-}
import Control.Lens

data SomeState = SomeState
  { _int :: Int,
    _string :: String }
makeLenses ''SomeState

I have functions that operate on parts of the state in SomeState. Let's say they also use a state monad:

updateInt :: Int -> State Int ()
updateString :: String -> State String ()

On the top-level I have a functions that deal with the whole SomeState.

updateSomeState :: Int -> State SomeState ()

I would like to call updateInt and updateString as part of updateSomeState. I have the feeling it should be possible to "convert" the SomeState state monad into a state monad for one of its parts using lense, but I fail to see how.

Any help is appreciated.

Upvotes: 1

Views: 368

Answers (1)

Lucy Maya Menon
Lucy Maya Menon

Reputation: 1590

I believe that you can do this with the zoom combinator from Control.Lens.Zoom:

{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Monad.State
data SomeState = SomeState { _int :: Int, _string :: String } deriving (Show)
makeLenses ''SomeState
updateInt :: Int -> State Int ()
updateInt x = id .= x
updateString :: String -> State String ()
updateString x = id .= x

updateSomeState :: Int -> State SomeState ()
updateSomeState x = zoom int (updateInt x)

GHCi:

*Main> runStateT (updateSomeState 5) (SomeState 3 "hi")
 Identity ((),SomeState {_int = 5, _string = "hi"})

Upvotes: 1

Related Questions