I'm new to Haskell. I'm developing a game-like simulation. I try to use lenses to update the state of the world.
Current iteration of code works, but looks clumsy. I am trying to improve it, e.g. I would like to:
- Get rid of direct enumeration of
q1
and so on, with usage ofquantityPolymorph
and others in them. Problem is that partial application won't help since the function which gets applied is "in the middle" of arguments; - Get rid of incrementQuantity. I'd like something like
fmap (+1)
, but sinceQuantity
is not an instance ofFunctor
, I can't do that. I can't makeQuantity
an instance because it has kind*
. Is there a more concise way, w/o lambda? - Update world with just lenses, if possible. It looks like simple dispatching and I think it might be possible to move away from direct specification of what lens (i.e.
quantityPolymorpth
) should be called for which argument (f
).
Important note: however the updateWorld
never emits Nothing
at the moment, I want to keep it returning a Maybe
because later at some point it will return Nothing
s as well.
How can I refactor my code? Are there other things amiss with it?
The source follows.
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Monad
import System.Random
data Quantity = Quantity Integer deriving (Show)
instance Random Quantity where
randomR (Quantity lo, Quantity hi) g =
let rand = randomR (lo, hi) g
(r, g1) = rand
in (Quantity r, g1)
random g =
let rand = random g
(r, g1) = rand
in (Quantity r, g1)
instance Eq Quantity where
(==) (Quantity q1) (Quantity q2) = q1 == q2
instance Ord Quantity where
(<=) (Quantity q1) (Quantity q2) = q1 <= q2
instance Num Quantity where
(+) (Quantity q1) (Quantity q2) = Quantity (q1 + q2)
(*) (Quantity q1) (Quantity q2) = Quantity (q1 * q2)
(-) (Quantity q1) (Quantity q2) = Quantity (q1 - q2)
abs (Quantity q) = Quantity (abs q)
signum (Quantity q) = Quantity (signum q)
fromInteger i = Quantity i
-------------------------------
data QuantityHolder = QuantityHolder { _quantityPolymorph :: Quantity
, _quantityTeamPlayer :: Quantity
, _quantityLoneWolf :: Quantity
} deriving (Show)
$(makeLenses ''QuantityHolder)
-------------------------------
data Fighter = TeamPlayer
| LoneWolf
| Polymorph
deriving (Show, Eq, Ord)
-------------------------------
data World = World {
_quantities :: QuantityHolder
} deriving (Show)
$(makeLenses ''World)
incrementQuantity (Quantity q) = Quantity (q + 1)
updateWorld :: Maybe World -> Fighter -> Maybe World
updateWorld (Just w) f =
case f of
Polymorph ->
Just $ q1 w
TeamPlayer ->
Just $ q2 w
LoneWolf ->
Just $ q3 w
where q1 = over quantities . over quantityPolymorph $ incrementQuantity
q2 = over quantities . over quantityTeamPlayer $ incrementQuantity
q3 = over quantities . over quantityLoneWolf $ incrementQuantity