I have a type constructor Token
and all of its data constructor take an Int
(the position where this token was encountered in the input) and maybe some payload:
data Token = EmptyToken Int -- just position
| ValueToken Int Int -- position and integer payload
| NameToken Int String -- position and string payload
When I want to obtain the position from a token, I end up with this quite cumbersome code:
position :: Token -> Int
position (EmptyToken position) = position
position (ValueToken position _) = position
position (NameToken position _) = position
This boiler plate makes me think that I am approaching the whole topic from the wrong direction.
What is the correct (or recommended) way to encode a data with some shared properties (like position) and some properties which are not shared?
Factor out the duplication in your data types just as you would your functions. Here's one way:
data Positioned a = Positioned Int a
data TokenData = Empty
| Value Int
| NameToken String
type Token = Positioned TokenData