Assignment 6
Home Up Assignment 1 Assignment 2 Assignment 3 Assignment 4 Assignment 5 Assignment 6 Assignment 7 Assignment 8

 

Qualified Types and Musical L-Systems

Due: Wed Oct 29 at noon.

Read Chapters 10 and 11 in HSOM.

  1. We have worked with several different Music types, such as Music Pitch,  Music (Pitch,Volume), and  Music (Pitch,[NoteAttribute]).  In the end though we usually want our music values to have type Music (Pitch,[NoteAttribute]), and we find ourselves having to write coercion functions to do this.  What would be nicer is the following:

    Define a type class called StdMusic having a single method:
    toStdMusic :: Music a -> Music (Pitch, [NoteAttribute])
    such that toStdMusic can be applied to any m :: Music T, as long as T is an instance of StdMusic, in each case yielding a value of type Music (Pitch, [NoteAttribute]).  Then define instances of StdMusic for Pitch, (Pitch, Volume), and (Pitch,[NoteAttribute]).

    The nice thing about this design is that if we have n types we no longer need to remember n-1 coercion functions -- we can just use toStdMusic, and in that sense you can view this as an overloading of the name.

    Note: to get this to work in GHC you will need to start GHCi with certain type extensions enabled, like this:
    > ghci -XFlexibleInstances -XTypeSynonymInstances
     
  2. Now define a type class called PrimEquiv with one method:
    (===) :: a -> a -> Bool
    such that x === y tells us whether or not "primitive musical values" x and y are "equivalent" from a "musical point of view".  For example, we would expect all of the following to be True:
    Cs === Df
    Note qn Cs === Note (1/4) Df
    cs 4 qn === df 4 qn
    Note qn (Cs,[Volume 5]) === Note qn (Df, [Volume (2+3)])

    To get all this to work, you will need to define instances of PrimEquiv for PitchClass, Pitch, Primitive a, (PitchClass,[NoteAttribute]), and Music a, although for the latter it should only work for primitive music values (i.e. an error should occur if non-primitive values are compared).
     
  3. Define an L-System grammar to create some "interesting" music using the functions defined in Chapter 10.
     
  4. Extend the L-System design in Chapter 10 to include a parallel construction; i.e. add a constructor (:=) to the LSys data type.