Skip to main content
Bounty Ended with 50 reputation awarded by Michael Pankov
added 672 characters in body
Source Link
nponeccop
  • 1.1k
  • 5
  • 10

If you want to be able to report any extra value from updateWorld you can use the existing state monad:

updateWorldS :: Fighter -> State World Bool
updateWorldS field = (quantities . atFighter field) <+= 1 >> return errorBool where
      errorBool = False -- or True

Or MonadPlus if you don't want to just report failure without extra info:

updateWorldS field = (quantities . atFighter field) <+= 1 >> when errorBool mzero where
      errorBool = False

Or MonadError if you want to supply an error value (of any type):

updateWorldS4 field = (quantities . atFighter field) <+= 1 >> when errorBool (throwError "Game over")

If you want to be able to report any extra value from updateWorld you can use the existing state monad:

updateWorldS :: Fighter -> State World Bool
updateWorldS field = (quantities . atFighter field) <+= 1 >> return errorBool where
      errorBool = False -- or True

Or MonadPlus if you don't want to just report failure without extra info:

updateWorldS field = (quantities . atFighter field) <+= 1 >> when errorBool mzero where
      errorBool = False

Or MonadError if you want to supply an error value (of any type):

updateWorldS4 field = (quantities . atFighter field) <+= 1 >> when errorBool (throwError "Game over")
added 450 characters in body
Source Link
nponeccop
  • 1.1k
  • 5
  • 10

Also note that lens interact with state monad transformer pretty well, so you may consider

updateWorldS :: Fighter -> State World Quantity
updateWorldS field = (quantities . atFighter field) <+= 1

Note that World is not passed in explicitly any more. And the type is more general than that, so you can combine state with IO and other monads should you wish:

updateWorldS :: MonadState World m => Fighter -> m Quantity

Also note that lens interact with state monad transformer pretty well, so you may consider

updateWorldS :: Fighter -> State World Quantity
updateWorldS field = (quantities . atFighter field) <+= 1

Note that World is not passed in explicitly any more. And the type is more general than that, so you can combine state with IO and other monads should you wish:

updateWorldS :: MonadState World m => Fighter -> m Quantity
added 758 characters in body
Source Link
nponeccop
  • 1.1k
  • 5
  • 10

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.

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 }

But it really depends on the usage scenarios you plan for World.

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.

added 214 characters in body
Source Link
nponeccop
  • 1.1k
  • 5
  • 10
Loading
added 497 characters in body
Source Link
nponeccop
  • 1.1k
  • 5
  • 10
Loading
added 497 characters in body
Source Link
nponeccop
  • 1.1k
  • 5
  • 10
Loading
added 497 characters in body
Source Link
nponeccop
  • 1.1k
  • 5
  • 10
Loading
Source Link
nponeccop
  • 1.1k
  • 5
  • 10
Loading