
Michael Mossey wrote:
A StaffItem can be one of several things. Let's say it can be a "chord" or a "control". I might like to define Chord and Control first:
data Chord = Chord { duration :: Double, notes :: [Note] } data Control = DynamicMark Int | TempoMark Int
Okay, so now I want to express the idea a StaffItem can be a Chord or a Control.
data StaffItem = StaffItemChord Chord | StaffItemControl Control
My problem is the awkward need for separately named constructors "StaffItemChord" and "StaffItemControl". Is there a better way? (Is this even right?)
Why not simply data StaffItem = Chord { duration :: Double, notes :: [Note] } | DynamicMark Int | TempoMark Int Unless you use Control and Chords in isolation, that's entirely fine. It's basically a question of how much type safety you want. If you have a function like chordName :: Chord -> String that should only with proper Chords and not Control messages, giving it the type signature chordName :: StaffItem -> String is less safe; the compiler won't complain if you pass it a Control message. If you want the compiler to complain, then building "type towers" as you did is the way to go. You can use predefined building blocks like Either type StaffLabel = Either Chord Control to build your types. There are a few methods for making things less clumsy available, like for example Wouter Swierstra. Data types à la carte. http://www.cse.chalmers.se/~wouter/Publications/DataTypesALaCarte.pdf Regards, apfelmus -- http://apfelmus.nfshost.com