This is probably a stupid question, but what does this trickery with GADTs and Existential Types give compared to the "normal" way?
import Data.Int (Int8, Int16)
import Data.ByteString (ByteString)
data ParsedImage
= ParsedAs8 (Int, Int, [Int8])
| ParsedAs16 (Int, Int, [Int16])
deriving Show
parseImage :: ByteString -> ParsedImage
parseImage = undefined
imageDimensions :: ByteString -> (Int, Int)
imageDimensions str =
case parseImage str of
ParsedAs8 (w, h, _) -> (w, h)
ParsedAs16 (w, h, _) -> (w, h)
Basically, the same way as a function can return an Either and everyone is happy to pattern-match on the result.