Lemming
Lemming

Reputation: 4205

Array element access with lens in the state monad

What is the recommended way to access an element of an array within the state monad with lens if the value type is not a monoid.

The following will fail to compile, because lens doesn't know what to do if there is no element at the given index i.

type MyArray = Array Int Char
-- accessElemInStateWrong :: Int -> State MyArray Char
-- accessElemInStateWrong i = use $ ix i

A working version can be implemented by combining gets from Control.Monad.State.Class with preview from Control.Lens.Fold.

accessElemInState :: Int -> State MyArray (Maybe Char)
accessElemInState i = gets $ preview $ ix i

This works just fine. However, given the plethora of functions and operators that lens defines, I was surprised to find that there doesn't seem to be one for this particular case.

So, my question is: Does lens define something like gets . preview? And if not, what's the recommended way to implement accessElementInState?


The reason why I'm asking is because lens does define a special operator outside of the state monad. While the following will not compile for the same reason as above.

-- accessElemWrong :: Int -> MyArray -> Char
-- accessElemWrong i a = a ^. ix i

We can use the operator (^?) to wrap the result in a Maybe and perform safe lookup.

accessElem :: Int -> MyArray -> Maybe Char
accessElem i a = a ^? ix i

Upvotes: 3

Views: 875

Answers (1)

Ian Henry
Ian Henry

Reputation: 22403

There is a function preuse that sounds like exactly what you're looking for:

accessElemInState :: Int -> State MyArray (Maybe Char)
accessElemInState i = preuse $ ix i

-- or
accessElemInState = preuse . ix

Upvotes: 2

Related Questions