
Am Montag 20 April 2009 02:10:42 schrieb Michael Mossey:
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]
What about import Data.Function (on) import Data.List convert namedStaffs = map timeVertical verticals where nameTimedChords (name,tcs) = [(time,name,chord) | (time, chord) <- tcs] timedNamedChords = sort . foldr merge [] . map nameTimedChords $ namedStaffs fst3 (x,_,_) = x verticals = groupBy ((==) `on` fst3) timedNamedChords timeVertical v@((t,_,_):_) = (t,[(name,chord) | (_,name,chord) <- v]) ?
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