All the time. I use it especially in state-based applications which are built using a combination of Lens
and MonadState
.
For example, on a project I’m working on now, I have a set of controllers (i.e. physical devices with buttons) and I need to keep track of the estimated state of each controller. I want to have a total map from controller name to controller state, implemented as a normal partial map with empty assumed to mean default. A simplified snippet to demonstrate what I mean:
data Button = U | D | L | R deriving ...
data ButtonState = Up | Down
instance Default ButtonState where def = Up
data ControllerState = ControllerState {buttons :: Map Button ButtonState, ...} deriving (Generic, ...)
instance Default ControllerState where def = ControllerState def ...
data Controller = A | B | C deriving ...
data SystemState = SystemState {controllers :: Map Controller ControllerState, ...} deriving (Generic, ...)
type AppMonad m = (MonadState SystemState m, ...)
pushButton :: AppMonad m => Controller -> Button -> m ()
pushButton controller button = #controllers . at controller . non def . #buttons . at button . non def .= Down
The above snippet will set the given button on the given controller to “down”, using “def” to interpret the meaning of an empty map entry. at
and non
come from Lens
, and the #buttons
syntax is OverloadedLabels plus generic-lens-labels
.