I've had quite some fun recently (re)learning Haskell.
My learning project is to implement braille music notation parsing
in Haskell. Given that i've already implemented most of this stuff
in C++, it gives me a great opportunity to rethink my algorithms.
Not everything I've had to implement until now was actually pretty.
I spent yesterday evening implementing accidentals handling, which turned out
to be quite a mess. However, I wanted to share my definition
of the circle of fifths, because I find it rather concise.
Given a key signature (often expressed as the number of sharp or flat
accidentals), tell which pitch classes are actually raised/lowered.
While reading through music notation software, I have seen several
implementations of this basic concept. However, I have
never seen one which was so concise.
module Accidental where
import Data.Map (Map)
import qualified Data.Map as Map (fromList)
import qualified Haskore.Basic.Pitch as Pitch
fifths n | n > 0 = let [a,b,c,d,e,f,g] = fifths (n-1)
| n < 0 = let [a,b,c,d,e,f,g] = fifths (n+1)
| otherwise = replicate 7 0
Given this, we can easily define a Map of pitches to currently
active accidentals/alterations. List comprehension to the rescue!
accidentals :: Int -> Map Pitch.T Pitch.Relative
accidentals k = Map.fromList [ ((o, c), a)
| o <- [0..maxOctave]
, (c, a) <- zip diatonicSteps $ fifths k
, a /= 0
maxOctave = 9
diatonicSteps = [Pitch.C, Pitch.D, Pitch.E, Pitch.F, Pitch.G,
The full source code for the haskore-braille (WIP) package
can be found on GitHub.
If you have any comments regarding the implementation, please
drop me a mail.