Using State monad with lens

Hi, I use the State monad in a lot of places, but when I use it with the lens library, I find myself writing code like: myFunc :: StateT MyState ([ResultType]) myFunc = do st <- get case st ^. some_property of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye" I want to do something based on a 'state-variable', but I have to write 'get' -- is there a pattern that allows me to avoid the intermediate 'st' variable? I want to write something like: myFunc = do case (get ^. some_property) of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye" but that won't compile. Best wishes, Mike

On Sat, 21 Mar 2020, Michael Hull wrote:
Hi,I use the State monad in a lot of places, but when I use it with the lens library, I find myself writing code like:
myFunc :: StateT MyState ([ResultType]) myFunc = do st <- get case st ^. some_property of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye" I want to do something based on a 'state-variable', but I have to write 'get' -- is there a pattern that allows me to avoid the intermediate 'st' variable?
gets (^. some_property) But you still need a local variable for the result of 'gets'.
I want to write something like:
myFunc = do case (get ^. some_property) of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye"
but that won't compile.
There cannot be an according accessor, because getting the state needs access to the state in the monad. One could at least think of using LambdaCase.

LambdaCase is useful for things like this. On Sat, Mar 21, 2020 at 10:50 PM Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sat, 21 Mar 2020, Michael Hull wrote:
Hi,I use the State monad in a lot of places, but when I use it with the lens library, I find myself writing code like:
myFunc :: StateT MyState ([ResultType]) myFunc = do st <- get case st ^. some_property of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye"
I want to do something based on a 'state-variable', but I have to write 'get' -- is there a pattern that allows me to avoid the intermediate 'st' variable?
gets (^. some_property)
But you still need a local variable for the result of 'gets'.
I want to write something like:
myFunc = do case (get ^. some_property) of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye"
but that won't compile.
There cannot be an according accessor, because getting the state needs access to the state in the monad. One could at least think of using LambdaCase._______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Normally, you'd write `gets` to access entries in your state environment according to some function (e.g. record accessors), but since `some_property` is itself (presumably) a `Lens` or `Getter`, you should be able to use the lensy-State accessor `use`( https://github.com/ekmett/lens/blob/e06c171840bbe86c789b8dff8c8211b88ac9211e... ). Then, your script becomes: ``` myFunc :: StateT MyState [ResultType] myFunc = do p ← use some_property case p of True → do my_value .= "Hello" False → do my_value .= "Goodbye" ``` `use` works in the same sense that `view` does for `MonadReader r m ⇒ m`. It even has an analog to `preview` called `preuse`, which you can use for `Prism`s in your state environment. Cheers, hope that helps, Emily On Sat, Mar 21, 2020 at 10:42 AM, Michael Hull < mikehulluk@gmail.com > wrote:
Hi, I use the State monad in a lot of places, but when I use it with the lens library, I find myself writing code like:
myFunc :: StateT MyState ([ResultType]) myFunc = do st <- get case st ^. some_property of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye"
I want to do something based on a 'state-variable', but I have to write 'get' -- is there a pattern that allows me to avoid the intermediate 'st' variable? I want to write something like:
myFunc = do case (get ^. some_property) of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye"
but that won't compile.
Best wishes,
Mike
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http:/ / mail. haskell. org/ cgi-bin/ mailman/ listinfo/ haskell-cafe ( http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe ) Only members subscribed via the mailman list are allowed to post.

Which as others have mentioned, works well with lambda case, here's an
example from a game I am writing:
```
runPhase :: (MonadIO m, MonadState GameState m) => Card -> m ()
runPhase c@Card {..} = use phase >>= \case
HeadlinePhase -> liftIO . putStrLn $ "Drew: " ++ show c
EventResolutionPhase -> liftIO . putStrLn $ "Event"
ArmyMovementPhase -> traverse_ moveArmy armyMovements
ActionPhase -> liftIO . putStrLn $ "Show me your moves!"
KaiserschlachtPhase -> pure ()
NationalWillPhase -> do
nw <- nationalWill
if nw <= -5 then gameOver else pure ()
GameOver -> liftIO . putStrLn $ "Game over"
```
On Sat, Mar 21, 2020 at 11:34 AM Emily Pillmore
Normally, you'd write `gets` to access entries in your state environment according to some function (e.g. record accessors), but since `some_property` is itself (presumably) a `Lens` or `Getter`, you should be able to use the lensy-State accessor `use`( https://github.com/ekmett/lens/blob/e06c171840bbe86c789b8dff8c8211b88ac9211e...). Then, your script becomes:
``` myFunc :: StateT MyState [ResultType] myFunc = do p ← use some_property case p of True → do my_value .= "Hello" False → do my_value .= "Goodbye" ```
`use` works in the same sense that `view` does for `MonadReader r m ⇒ m`. It even has an analog to `preview` called `preuse`, which you can use for `Prism`s in your state environment.
Cheers, hope that helps, Emily
On Sat, Mar 21, 2020 at 10:42 AM, Michael Hull
wrote: Hi, I use the State monad in a lot of places, but when I use it with the lens library, I find myself writing code like:
myFunc :: StateT MyState ([ResultType]) myFunc = do st <- get case st ^. some_property of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye"
I want to do something based on a 'state-variable', but I have to write 'get' -- is there a pattern that allows me to avoid the intermediate 'st' variable? I want to write something like:
myFunc = do case (get ^. some_property) of True -> do my_value .= "Hello" True -> do my_value .= "Goodbye"
but that won't compile.
Best wishes,
Mike
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

I'm surprised noone has mentioned 'zoom' yet. It does not make your original example work directly, but almost. It may be very useful to keep in mind as a way to do whatever you want. http://hackage.haskell.org/package/lens-4.19.1/docs/Control-Lens-Zoom.html#v... The idea of zoom is that you use it like so: zoom my_lens my_monadic_action where my_monadic_action is a monadic action that works on the sub-element (call it 's') of the state, and the entire thing 'zoom my_lens my_monadic_action' is then a monadic action that works on the whole element (call it 't'). my_lens is a lens that focuses on 's' within 't'. So instead of using the lens all the time in the monadic action, you're basically saying: "Put this everywhere that you need to", and then you can do things with the sub-element 's'. Juan. PS: I hope I did not severely misunderstand what you wanted, but it's still a possibility. -- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336.

Thankyou everybody - this is really helpful, especially the \case technique.
@Juan I am not sure my Haskell is strong enough to use zoom yet, but I will
look into it!
Thanks again.
Mike
On Sat, 21 Mar 2020 at 21:12, Juan Casanova
I'm surprised noone has mentioned 'zoom' yet. It does not make your original example work directly, but almost. It may be very useful to keep in mind as a way to do whatever you want.
http://hackage.haskell.org/package/lens-4.19.1/docs/Control-Lens-Zoom.html#v...
The idea of zoom is that you use it like so:
zoom my_lens my_monadic_action
where my_monadic_action is a monadic action that works on the sub-element (call it 's') of the state, and the entire thing 'zoom my_lens my_monadic_action' is then a monadic action that works on the whole element (call it 't'). my_lens is a lens that focuses on 's' within 't'.
So instead of using the lens all the time in the monadic action, you're basically saying: "Put this everywhere that you need to", and then you can do things with the sub-element 's'.
Juan.
PS: I hope I did not severely misunderstand what you wanted, but it's still a possibility.
-- The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (6)
-
Emily Pillmore
-
Henning Thielemann
-
Juan Casanova
-
Matt Mongeau
-
Michael Hull
-
William Yager