I have some datatypes along the line of
data Outer = Outer { _list :: [ Inner ] }
data Inner = Inner { _bool :: Bool }
using Control.Lens, I can access the _bool of the ith Inner (inside a 'State Outer' monad) like this
boolValue <- gets (^. list . to (!! i) . inner)
I would like to also be able to update this value with something like
list ^. (to (!! i)) ^. inner %= True
However (by my understanding), the 'to' function only creates a getter, not a true lens that can be used as either getter or setter.
So, how can I convert (!! i) into a lens that will allow me to update this field?
You can't* turn
(!!)
into any lens-like thing other than aGetter
-- but there's a function to do this sort of thing: ix, for accessing things at indices. It's actually aTraversal
, not aLens
-- which, here, just means that it can fail (if the index is out of bounds) -- but as long as the index is in the list, it'll work.There's another problem, though --
(^.)
is also an operator that's used exclusively for getting values. It's incompatible with e.g.(%=)
, which takes a lens-like thing as its first argument. And:(%=)
is for mapping a function over the existing value; if you just want to set, you can use(.=)
. So you probably want something like:* There actually is a function that can do this -- it's called
upon
-- but it uses wonderful evil black magic and you shouldn't use it, at least not for this (and probably not for any real code).Use
element
, which is aTraversal
to the specified list element:If you want to get the list element you must do so using a
Maybe
since the list element might not be there: