Podczas pracy nad stanem o nazwie AppState
chcę śledzić liczbę instancji, powiedzmy. Te wystąpienia mają różne identyfikatory typu: InstanceId
.Jak używać soczewek do wyszukiwania wartości na mapie, zwiększania jej lub ustawiania na wartość domyślną
Dlatego mój wygląd stan lubi to
import Control.Lens
data AppState = AppState
{ -- ...
, _instanceCounter :: Map InstanceId Integer
}
makeLenses ''AppState
funkcji, aby śledzić liczy powinna przynieść 1, gdy nie ma instancji z podanym identyfikatorze została liczone przed i n + 1
inaczej:
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
ile powyższy kod działa, jest nadzieja, że uda się go poprawić. Co mi się nie podoba:
- muszę wywołać mapę
instanceCounter
dwukrotnie (pierwszy do ustawiania, a następnie na uzyskanie wartości) - używam
fromMaybe
gdzie zawszeJust
oczekuje się (a więc równie dobrze mogę używaćfromJust
) - Nie używam soczewek do wyszukiwania i wstawiania w
incOrSetToOne
. Powodem jest to, żeat
nie pozwala obsłużyć przypadku, w którymlookup
dajeNothing
, ale zamiast tego s nadMaybe
.
Sugestie do poprawy?
Czuję, że jeszcze nie w pełni rozumiałem "w" ... teraz "Po prostu ... Po prostu" wygląda na zbędny. Muszę jeszcze trochę eksperymentować, ale tego właśnie szukałem. –
OK, więc kluczem dla mnie było zrozumienie funkcji [alter] (http://hackage.haskell.org/package/containers-0.5.6.3/docs/Data-Map-Strict.html#v:alter), która ma w swoim podpisie funkcję 'Może a -> Może a' ustawić lub anulować wartości map. –
I jeśli chodzi o poprawę, odpowiedzi glguy są na topie. Przepraszam! –