yornaath / Dungeon-Of-Xuul-Text-Adventure

Text adventure engine in Purescript. Low on content yet.
0 stars 1 forks source link

Use phantom types for Stats #2

Open ursi opened 4 years ago

ursi commented 4 years ago

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
-}
yornaath commented 4 years ago

Yes this looks good! 👍