updateWorld
of @Changaco can still be improved. I'll show it gradually so you can see what's going on.
Firstly, we can eliminate duplication in case
statement and use lens composition to eliminate second over
:
quantity Polymorph = quantityPolymorph
quantity TeamPlayer = quantityTeamPlayer
quantity LoneWolf = quantityLoneWolf
updateWorld :: Fighter -> World -> World
updateWorld fighter w = increment (quantity fighter) w where
increment field = over (quantities . field) (+1)
Then we can go pointfree. Pointfree is all about readability so don't do it whenever you feel readability is harmed. With coding experience more and more code will become readable for you.
updateWorld = increment . quantity where
increment field = over (quantities . field) (+1)
Then we replace over
with a more specialized version of it from Control.Lens.Setter
:
updateWorld = increment . quantity where
increment field = (quantities . field) +~ 1
Now it seems beneficial to inline increment
. I'll do in 2 steps. First, I make the actual parameter of increment
explicit:
updateWorld field = increment $ quantity field where
increment field = (quantities . field) +~ 1
Then I inline:
updateWorld :: Fighter -> World -> World
updateWorld field = (quantities . quantity field) +~ 1
Another way to improve could be to use a Map
or an Array
for QuantityHolder
:
data World = World { _quantities :: M.Map Fighter Quantity }
Below is full source using Map
:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Control.Lens
import System.Random
import qualified Data.Map as M
import Data.Maybe
newtype Quantity = Quantity Integer
deriving (Eq,Num,Ord,Random,Show)
data Fighter = TeamPlayer
| LoneWolf
| Polymorph
deriving (Eq,Ord,Show)
data World = World { _quantities :: M.Map Fighter Quantity }
deriving (Show)
$(makeLenses ''World)
atFighter i = at i . iso fromJust Just
updateWorld :: Fighter -> World -> World
updateWorld field = (quantities . atFighter field) +~ 1
But it really depends on the usage scenarios you plan for World
.