При работе с состоянием под названием AppState
я хочу отслеживать количество, скажем, экземпляров. Эти экземпляры имеют разные идентификаторы типа InstanceId
.
Поэтому мое состояние выглядит так
import Control.Lens
data AppState = AppState
{ -- ...
, _instanceCounter :: Map InstanceId Integer
}
makeLenses ''AppState
Функция для отслеживания количества должна возвращать 1, если ни один экземпляр с данным идентификатором не был подсчитан ранее, и n + 1
в противном случае:
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
Хотя приведенный выше код работает, надеюсь, есть способ его улучшить. Что мне не нравится:
- Я должен вызвать карту
instanceCounter
дважды (сначала для установки, затем для получения значения) - Я использую
fromMaybe
там, где всегда ожидаетсяJust
(поэтому я мог бы также использоватьfromJust
) - Я не использую линзы для поиска и вставки в
incOrSetToOne
. Причина в том, чтоat
не позволяет обрабатывать случай, когдаlookup
даетNothing
, а вместо этогоfmap
s большеMaybe
.
Предложения по улучшению?