Overly complicated parser combinator
boiler :: ReadP Boiler
boiler
  =   Hobbyist &lt;$ char 'H'
  &lt;|&gt; Locomotive &lt;$ char 'L'
  &lt;|&gt; flip Boiler &lt;$ char 'B'
    &lt;*&gt; (HighPressure &lt;$ char 'H' &lt;|&gt; LowPressure &lt;$ char 'L')
    &lt;*&gt; ((,,) &lt;$ char '-'
      &lt;*&gt; (read &lt;$&gt; munch1 isDigit) &lt;* char 'x'
      &lt;*&gt; (read &lt;$&gt; munch1 isDigit) &lt;* char 'x'
      &lt;*&gt; (read &lt;$&gt; munch1 isDigit))


By changing the internal definition of Boiler you can clean up that flip.

By also changing the user interface you can use the Read instance deriver:

data Boiler = H | L | BL Int Int Int | BH Int Int Int deriving (Read, Show)


Your example would then look like BH 3 3 4.

By the way, whereever you're using the Eq instance of Tank, consider pattern matching instead.