Suppose I have the following:
class Shape a where
draw a :: a -> IO ()
data Rectangle = Rectangle Int Int
instance Shape Rectangle where
draw (Recta
If you really do need to do this, then use an existential:
{-# LANGUAGE GADTs #-}
class IsShape a where
draw :: a -> IO ()
data Rectangle = Rectangle Int Int
instance IsShape Rectangle where
draw (Rectangle length width) = ...
data Circle = Circle Int Int
instance IsShape Circle where
draw (Circle center radius) = ...
data Shape where
Shape :: IsShape a => a -> Shape
shapes = [Shape (Circle 5 10), Shape (Circle 20 30), Shape (Rectangle 10 15)]
(I renamed your class as there would be a name clash with the datatype otherwise, and having the naming this way round seems more natural).
The advantage of this solution over the other answer involving a single datatype with different constructors is that it is open; you can define new instances of IsShape
wherever you like. The advantage of the other answer is that it's more "functional", and also that the closedness may in some cases be an advantage as it means that clients know exactly what to expect.