| |
Introduction to Haskell and Haskore
Due: Monday Sept 15 at noon.
In this assignment you will become familiar with GHC, Haskell, and Haskore.
- Read Chapters 1-3 of HSOM (The Haskell School of Music).
- 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.)
- Open a Command Prompt window and cd to Haskore/example. Fire up GHCi
and start getting familiar with it. For example, try the following:
 | :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. |
 | :reload
This is handy for reloading the last program, without having to type the
name again. Note that :r is shorthand
for :reload. |
 | play childSong6
play ssf
play cms
These are all expressions whose evaluation results in MIDI output for the
corresponding tune. |
 | childSong6
By typing just the tune name of the Music value, Haskell will print the
value to the terminal. |
 | :t play
:type childSong6
:type ssf
This returns the type of an expression. As usual,
:t is a shorthand for
:type. |
 | :info Music
This returns information about things, in this case the definition of the
Music data type. Note that :i is a
suitable shorthand. |
 | :?
This will list all of the GHC commands at your disposal. |
 | Open 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. |
Finally, create your own Haskore program as follows:
 | Create a new file with a text editor, with the name is "HW1.lhs". |
 | Start 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
"> ". |
 | In 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. |
 | Email 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.
- 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)).
- 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.
- 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:
- 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.
|