Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use Control.Lens to update the ith element of a list?

Tags:

haskell

lenses

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?

like image 795
ajp Avatar asked Jun 09 '13 05:06

ajp


1 Answers

You can't* turn (!!) into any lens-like thing other than a Getter -- but there's a function to do this sort of thing: ix, for accessing things at indices. It's actually a Traversal, not a Lens -- 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:

list . ix i . inner .= True

* 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).

like image 153
shachaf Avatar answered Sep 27 '22 18:09

shachaf