Search code examples
haskellhaskell-lens

How can I use Lenses to perform read-only monadic operation over a sequence held in some state?


My data structure looks more or less like this (simplified for the purpose of the question)

data GameObject = GameObject { _num :: Int }
data Game = Game { _objects :: [GameObject] }

I use makeLenses to generate the accessors for both of those. Thus, I am able to do operations en masse like this:

-- loop :: MonadState with Game inside
loop = objects.traversed.num += 1

And this is great.


However, I can't find a way to do an equivalent of this (printing every num):

game <- get
let objects = _objects game
let objectNums = map _num objects
mapM_ print objectNums

I have tried things like

uses (objects.traversed.num) >>= mapM_ print

but the only way I see to use traversed with some state like that involves using monoids, and I don't want to combine the fields; I want to run a monadic action over a part of every element in the elements from some sequence that resides in my state.

So, is this possible using some provided Lens function or do I have to write that myself, somehow?


Solution

  • What about

    mapMOf_ (objects . traversed . num) print
    

    or if you want to apply that to the state of a state monad,

    get >>= mapMOf_ (objects . traversed . num) print
    

    ? (Perhaps there's a more lens-like way to combine the first line with the state of a state monad. If so, I'd like to learn about it myself.)