I will briefly explain my chain of thought before the example so that if any of it does not make sense we are able to fix that as well.
Suppose that for each type constructor of my data declaration (a sum of product types) there is one parameter that has an instance to a given type class. In my head, that means that I would be able to explain to GHC/Haskell how to get to that specific type so that my type would end up behaving like an instance of that type class.
For example:
data Vector
-- The class type I talked about
class Transformable a where
setPosition' :: Vector -> a -> IO ()
setOrigin' :: Vector -> a -> IO ()
setAngle' :: Float -> a -> IO ()
-- ... this goes a long way
data TCircleShape
data TSquareShape
data TTriangleShape
data TConvexShape
-- Large sum type that defines different types of Shape
data Shape = Circle Float TCircleShape
| Square Float String TSquareShape
| Triangle Float TTriangleShape
| Convex [Vector] Float TConvexShape
-- ...
-- Almost all of the the Shape constructors have at least one
-- parameter that has an instance of the Transformable typeclass:
instance Transformable TCircleShape
instance Transformable TSquareShape
instance Transformable TTriangleShape
instance Transformable TConvexShape
-- What I would like to write then is:
runOnTransformable :: Transformable a => (a -> IO ()) -> Shape -> IO ()
runOnTransformable = undefined -- (???)
-- What I am doing right now is simply expanding Shape manually:
setShapePosition :: Vector -> Shape -> IO ()
setShapePosition v (Circle _ ptr) = setPosition' v ptr
setShapePosition v (Square _ _ ptr) = setPosition' v ptr
-- and so on...
setShapeAngle' :: Float -> Shape -> IO ()
setShapeAngle' f (Circle _ ptr) = setAngle' f ptr
setShapeAngle' f (Convex _ _ ptr) = setAngle' f ptr
-- and so on...
There is a clear pattern in my eyes and I would like to have some way of abstracting this unwrapping somehow.
One might try to have an instance for the data type itself:
instance Transformable Shape where
setPosition' v (Circle _ ptr) = setPosition' v ptr
-- [...]
setAngle' f (Convex _ _ ptr) = setAngle' f ptr
-- [...]
The downside is that I would have to 'reimplement' all the methods by manually unwrapping the type classes again, except it is in an instance declaration. Right?
Coming back to my question: Is there a way to inform Haskell how to unwrap and act upon a type class from a sum type?
I have a really thin familiarity with Lens and none with TemplateHaskell, however, if using said features would be a probable solution, by all means, go for it.