
Some additional thoughts: Here is something I'm struggling with. Let's say a piece of music is several staves filled with chords. Staves have names. Each chord in a staff has a time. In informal notation: staff "fred": (time 1.0, chord 1), (time 1.5, chord 2), (time 2.0, chord 3) staff "bob" : (time 1.0, chord 4), (time 2.0, chord 5) When laying out music, I need to find "verticals", which are chords located on different staves which happen to coincide in time. For instance, the above has three verticals: time 1.0: ("fred", chord 1), ("bob", chord 4) time 1.5: ("fred", chord 2) time 2.0: ("fred", chord 3), ("bob", chord 5) I want to write a function that converts the first way of organizing the information into the second. I tried writing types like type Chord = ... type Time = Double type Name = String type TimedChord = (Time,Chord) type Staff = [(Time,Chord)] type NamedStaff = (Name,Staff) type NamedChord = (Name,Chord) type Vertical = [NamedChord] type TimedVertical = (Time,Vertical) The function I want is convert :: [NamedStaff] -> [TimedVertical] As you can imagine, this is a confusing mess, with all these variants on named and timed things. I thought it might help to create functors called Named and Timed, which might help abstracting operations on named and timed things. For example, datatype Named a = Named { namedName :: Name, namedData :: a } instance Functor Named = name a :: Name name a = namedName a x `fmap` f = Named { namedName = namedName x, namedData = f $ namedData x } Any other suggestions? Thanks, Mike