1

For my uni homework we have to make a PvZ like simple game in Haskell.

I have a Plant type (the integer represents it's health)

data Plant =  Peashooter Int | Sunflower Int | Walnut Int | CherryBomb Int deriving (Show, Eq, Ord)

and I would like to make a function, that takes said Plant type, and returns a boolean value based on if it's health is positive or not.

isPlantAlive :: Plant -> Bool

I tried some solutions, and what works is the following pattern-matching:

isPlantAlive :: Plant -> Bool
isPlantAlive (Peashooter health) = health /= 0
isPlantAlive (Sunflower health) = health /= 0
isPlantAlive (Walnut health) = health /= 0
isPlantAlive (CherryBomb health) = health /= 0

My question is basically this:

Is there a cleaner/better way to do this?

What I expected to also work, was something like this, to match all Plant types, no matter the constructor:

isPlantAlive :: Plant -> Bool
isPlantAlive (Plant health) = health /= 0

Thank you for your help.

MGR4
  • 57
  • 7

1 Answers1

6

I think the best approach is to refactor the data type to make the common field explicit. Consider instead:

data Plant = Plant { health :: Int, species :: Species } deriving (Show,Eq,Ord)
data Species = Peashooter | Sunflower | Walnut | CherryBomb deriving (Show,Eq,Ord)

This gives you the function health :: Plant -> Int for free, and:

isPlantAlive :: Plant -> Bool
isPlantAlive p = health p > 0

Technically, there are alternatives. The following will work, as Haskell groups together the health fields into a single field selector function that works across all constructors. (If some constructors didn't include a health field, the function would raise an exception if used on them.)

data Plant
  = Peashooter { health :: Int}
  | Sunflower { health :: Int }
  | Walnut { health :: Int }
  | CherryBomb { health :: Int }
  deriving (Show, Eq, Ord)

isPlantAlive :: Plant -> Bool
isPlantAlive p = health p > 0

Of course, that's almost as much boilerplate as writing a pattern-matched version of health directly.

K. A. Buhr
  • 45,621
  • 3
  • 45
  • 71