Thanks!
This helps reduce the number of field names, but it does not address the main problem, which is the obligation of pattern matching on all constructors.
The Person type is just a simple example. If you have a lot of constructors repeating all of them without a real reason can be time-consuming and boring.
I am aware that the real reason of the problem may be a wrong architecture, but I still have the feeling that my solution does have some use cases.
If you use a sum type, you *always* need to check every case. That is what you sign up for. If you want to express a commonality that should expressed in the type [1]. Otherwise if you extend Person with a constructor that has *no* notion of age then you cannot have a total function from Person -> Int. You would want something like a Prism or just a simple function from Person -> Maybe Int. Try to avoid non-total functions. That way lies madness.
[1] as has already been suggested, this involves factoring out the things that are common from the things that aren't
data SomeSum = Part1 String | Part2 Int | Part3
data Common a = Common Int a
data Composite = Common SomeSum
Now you can see that a function wanting the common Int must necessarily succeed when applied to Composite, but that there is no total function Composite -> String that accesses the String value held by Part1. I hope this is useful to you.