Haskell Language Stateful Lenses


Example

Lens operators have useful variants that operate in stateful contexts. They are obtained by replacing ~ with = in the operator name.

(+~) :: Num a => ASetter s t a a -> a -> s -> t
(+=) :: (MonadState s m, Num a) => ASetter' s a -> a -> m ()

Note: The stateful variants aren't expected to change the type, so they have the Lens' or Simple Lens' signatures.

Getting rid of & chains

If lens-ful operations need to be chained, it often looks like this:

change :: A -> A
change a = a & lensA %~ operationA
             & lensB %~ operationB
             & lensC %~ operationC

This works thanks to the associativity of &. The stateful version is clearer, though.

change a = flip execState a $ do
    lensA %= operationA
    lensB %= operationB
    lensC %= operationC

If lensX is actually id, the whole operation can of course be executed directly by just lifting it with modify.

Imperative code with structured state

Assuming this example state:

data Point = Point { _x :: Float, _y :: Float }
data Entity = Entity { _position :: Point, _direction :: Float }
data World = World { _entities :: [Entity] }

makeLenses ''Point
makeLenses ''Entity
makeLenses ''World

We can write code that resembles classic imperative languages, while still allowing us to use benefits of Haskell:

updateWorld :: MonadState World m => m ()
updateWorld = do
    -- move the first entity
    entities . ix 0 . position . x += 1

    -- do some operation on all of them
    entities . traversed . position %= \p -> p `pointAdd` ...

    -- or only on a subset
    entities . traversed . filtered (\e -> e ^. position.x > 100) %= ...