look how much you can simplify your stats module using phantom types
module Game.Data.Stats where
import Prelude
import Data.Argonaut.Decode (class DecodeJson)
import Data.Argonaut.Encode (class EncodeJson)
import Data.Foldable (foldl)
data Agility
data Strength
data Endurance
data Wisdom
data Intelligence
-- this is the "phantom type"
newtype Stat a
= Stat Int
derive newtype instance eqStat :: Eq (Stat a)
derive newtype instance showStat :: Show (Stat a)
derive newtype instance semiringStat :: Semiring (Stat a)
derive newtype instance encodeJsonStat :: EncodeJson (Stat a)
derive newtype instance decodeJsonStat :: DecodeJson (Stat a)
{-
depending on how this is used elsewhere, you might want to define helper functions for creating specific stats, e.g.
agility :: Int -> Stat Agility
agility = Stat
but it wasn't needed for what's in here
-}
newtype Stats
= Stats
{ agi :: Stat Agility
, str :: Stat Strength
, end :: Stat Endurance
, wis :: Stat Wisdom
, int :: Stat Intelligence
}
derive newtype instance eqStats :: Eq Stats
derive newtype instance showStats :: Show Stats
derive newtype instance semiringStats :: Semiring Stats
derive newtype instance encodeJsonStats :: EncodeJson Stats
derive newtype instance decodeJsonStats :: DecodeJson Stats
mkStats :: Int -> Int -> Int -> Int -> Int -> Stats
mkStats agi str end wis int =
Stats
{ agi: Stat agi
, str: Stat str
, end: Stat end
, wis: Stat wis
, int: Stat int
}
emptyStats :: Stats
emptyStats =
Stats
{ agi: Stat 0
, str: Stat 0
, end: Stat 0
, wis: Stat 0
, int: Stat 0
}
total :: Array Stats -> Stats
total statsList = foldl (+) emptyStats statsList
{-
this still has the saftey you want
if you try doing this
bad = (Stat 1 :: Stat Agility) + (Stat 1 :: Stat Strength)
you'll get a nice type error
[PureScript TypesDoNotUnify] [E] Could not match type
Strength
with type
Agility
-}
look how much you can simplify your stats module using phantom types