While working on a state called AppState
I want keep track of the number of, say, instances. These instances have distinct ids of type InstanceId
.
Therefore my state look likes this
import Control.Lens
data AppState = AppState
{ -- ...
, _instanceCounter :: Map InstanceId Integer
}
makeLenses ''AppState
The function to keep track of counts should yield 1 when no instance with given id has been counted before and n + 1
otherwise:
import Data.Map as Map
import Data.Map (Map)
countInstances :: InstanceId -> State AppState Integer
countInstances instanceId = do
instanceCounter %= incOrSetToOne
fromMaybe (error "This cannot logically happen.")
<$> use (instanceCounter . at instanceId)
where
incOrSetToOne :: Map InstanceId Integer -> Map InstanceId Integer
incOrSetToOne m = case Map.lookup instanceId m of
Just c -> Map.insert instanceId (c + 1) m
Nothing -> Map.insert instanceId 1 m
While the above code works, there is hopefully a way to improve it. What I don't like:
- I have to evoke the map
instanceCounter
twice (first for setting, then for getting the value) - I use
fromMaybe
where alwaysJust
is expected (so I might as well usefromJust
) - I don't use lenses for the lookup and insertion in
incOrSetToOne
. The reason is thatat
does not allow to handle the case wherelookup
yieldsNothing
but insteadfmap
s overMaybe
.
Suggestions for improvement?
at
yet ... now theJust ... Just
looks redundant. I gotta experiment some more, but that's indeed what I was looking for. – Gervais