The Sky Language

I like writing programming languages. Solving a problem is satisfying, but creating a vocabulary to describe solutions to an entire class of problems is a much deeper satisfaction. Right now I’m working on a language called Sky. It is unique in that it addresses a problem domain entirely separate from typical computational problems: musical creation.

In the world of music-oriented programming languages or projects, there are some really great open source projects. Lilypond is an engraver (sheet music typesetter for the laymen) with a whole ecosystem around it. Frescobaldi, for example, is a graphical Lilypond editor. Lilypond addresses the problem of creating a music engraving (i.e. sheet music) given predefined music. Sky is something different: it addresses the problem of writing the music itself. You can think of it as an instrument, or perhaps an assistive compositional tool.

To instantiate some of the abstract claims I’ve made, let’s take a look at some syntax. Forgive the lack of syntax highlighting, my language is not yet popular enough to be supported by Markdown renderers!

-- Creates a basic I-V-I chord progression in the key of C.
fn main(): song {
    chord one = major_chord(C4) quarter;
    chord five = major_chord(G4) quarter;

    compose [one, five, one];

-- Given a note, returns a major chord with that note as the root.
fn major_chord(input: pitch): notes {
    pitch root  = input;
    pitch third = input + 4; -- add four semitones (a major third) to the input note
    pitch fifth = input + 7; -- add seven semitones (a perfect fifth) to the input note

    return [root, third, fifth];

This style of syntax will be familiar to anybody who has worked with a language with C-style syntax. This is not a tutorial post, so I won’t go into a line-by-line breakdown.

Sky’s primitive types reflect that it addresses a fundamentally different problem space. There are still numbers and booleans, as they are necessary for control flow via conditionals and iteration, but that’s where the similarities end. Sky supports pitches, notes, chords, rhythms, and scale degrees as primitive types. There are also higher level generic types like lists. A list of pitches, for example, can be converted into either a chord by assigning a rhythm to the whole list. That same list of pitches can be converted into a melody by mapping rhythms onto each individual note in the list.

notes melody = map [c3, d3, e3] with quarter;
chord c_major = [c3, e3, g3] quarter;

The output of the Sky compiler is not a runnable binary or bytecode. It is configurable to be many things, but the two compilation targets I prioritize are Lilypond and Midi. The Lilypond toolchain allows Sky to then generate sheet music, other formats of MIDI, and much more.

Lilypond is still in the early stages of development right now. I have finished the lexer and have begun work on what I’m tentatively calling the “runtime”. which is the evaluation stage where the syntax tree is converted into Lilypond and Midi. This is indeed blurring the lines of what are traditionally considered runtime and compilation time.

Stay tuned for more updates on Sky.


Now read this

I got a Rust job.

I have been a hobbyist Rust programmer for about five years now. I have given a couple of conference talks, I’ve written a few crates, and I almost understand lifetimes. All of my personal projects since 2014 have been written in Rust,... Continue →