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

 

Introduction to Haskell and Haskore

Due: Monday Sept 15 at noon.

In this assignment you will become familiar with GHC, Haskell, and Haskore.

  1. Read Chapters 1-3 of HSOM (The Haskell School of Music).
  2. Follow the instructions on the "Software Resources" link, to install GHC, darcs, and Haskore on your computer.  (Alternatively, get a Zoo account so that you can use a Zoo machine.)
  3. Open a Command Prompt window and cd to Haskore/example.  Fire up GHCi and start getting familiar with it.  For example, try the following:
    bullet:load HaskoreExamples.lhs
    Note that :l is a suitable shorthand for :load, and you also can leave off the .lhs extension on the file name.
    bullet:reload
    This is handy for reloading the last program, without having to type the name again.  Note that :r is shorthand for :reload.
    bulletplay childSong6
    play ssf
    play cms

    These are all expressions whose evaluation results in MIDI output for the corresponding tune.
    bulletchildSong6
    By typing just the tune name of the Music value, Haskell will print the value to the terminal.
    bullet:t play
    :type childSong6
    :type ssf
    This returns the type of an expression.  As usual, :t is a shorthand for :type.
    bullet:info Music
    This returns information about things, in this case the definition of the Music data type.  Note that :i is a suitable shorthand.
    bullet:?
    This will list all of the GHC commands at your disposal.
    bulletOpen a text editor on Haskore/examples/HaskoreExamples.lhs and note the other values that are defined there.  Play with using the above commands at the GHCi prompt.
  4. Finally, create your own Haskore program as follows:
    bulletCreate a new file with a text editor, with the name is "HW1.lhs".
    bulletStart the file with the following header:
    > module HW1 where
    > import Haskore
    Note that, because we are creating a .lhs ("literate Haskell") file, each of our lines of program code must begin with "> ".
    bulletIn the remainder of the file, create solutions to the programming problems listed below.  Once you are ready to try running something, cd to the directory in which you created the file, start GHCi, and type:
    :l HW1
    Then, as you did above with HaskoreExamples.lhs, you can interact with the values in your program.
    bulletEmail your solution (i.e. the file HW1.lhs) to Eric Cheng (our TA).

Here are the programming problems.  You should make an attempt to write the solutions as elegantly and succinctly as possible.

  1. Define a function chrom :: Pitch -> Pitch -> Music Pitch such that chrom p1 p2 is a chromatic scale of quarter-notes whose first pitch is p1 and last pitch is p2.  If p1 > p2, the scale should be descending, otherwise it should be ascending.  If p1 == p2, then the scale should contain just one note.  (A chromatic scale is one whose successive pitches are separated by one absolute pitch (i.e. one semitone)).
  2. Abstractly, a scale can be described by the intervals between successive notes.  For example, the 8-note major scale can be defined as the sequence of 7 intervals [2,2,1,2,2,2,1], and the 12-note chromatic scale by the 11 intervals [1,1,1,1,1,1,1,1,1,1,1].  Define a function mkScale :: Pitch -> [Int] -> Music Pitch such that mkScale p ints is the scale beginning at pitch p and having the intervallic structure ints.
  3. Write the melody of "Frere Jacques" (or, "Are You Sleeping") in Haskore.  Try to make it as succinct as possible.  Then, using functions already defined, generate a four-part round, i.e. four identical voices, each delayed successively by two measures.  Use a different instrument to realize each voice.

    For CPSC 531 grad students only:
  4. Prove that, if p2 >= p1:
    chrom p1 p2 == mkScale p1 (take (absPitch p2 - absPitch p1) (repeat 1))
    Please note that, depending on how you define chrom and mkScale, this proof might not be easy, as it might require induction, and it might not even be true!  The reason it might not be true is that if you use "line" in one definition and not in the other, you might get a random "rest 0" at the end of one phrase, and not the other.  So even though the two music values will sound the same when you play them, they are technically not equal as Haskell values.  When working on your proof, feel free to assume, for example, that:
    line (note sn (pitch (absPitch p1)))  ==  note sn p1
    even though it's not really true...  Also, I have a version of mkScale that uses the list function scanl, which I haven't told you about, and for which I use the lemma:
    [m..n] = scanl (+) m (take (n-m) (repeat 1))
    In any case, give it your best shot, but don't stress out over it if you can't get the proof to go through entirely.