Patterns in Haskell

I’ve been trying to make music with Haskell for a little while now. One thing about Haskell is that its strict typing forces you to think a lot about how you represent things.

I wanted to support two things in my musical pattern representation, firstly polyphony (more than one sound being triggered at the same time) and secondly recursive structure. In the west we often think of rhythm in quite `flat’ terms – a 2d pattern like this:

Of course that’s a pretty useful techno interface, allows for polyphony, and could be represented in haskell using a straightforward list of lists. However this 2D structure is only really suitable for making music with fixed timed signatures, most notably 4/4.

Time: you’re doing it completely wrong

Enter Bernard Bel (pictured right). His BP2 software represents music in a manner inspired by Indian classical music. His 2001 paper Rationalising musical time has all the details and is a great read, formalising a quite beautiful way of thinking about time. As part of that it defines an elegant pattern syntax that allows patterns to be embedded inside patterns of differing time signatures.

Here’s my first attempt at representing analogous structures in Haskell. Straightforwardly, a musical event is either a sound (represented by some string) or some silence:

data Event = Sound String
| Silence

A musical structure is either an event, a cycle of structures, or a polymetry of structures:

A cycle allows us to sequence structures one after another, and a polymetry allows us to represent several structures occuring over the same period of time. If the structures within a Polymetry have different durations, then they are ‘stretched’ until they are the same length (equal to the lowest common multiple of their lengths). I’ve written something in parsec that parses Bel’s notation into the Structure datatype.

The problem with the above representation is that it gets unwieldy with complex rhythmic structures. The whole point of generative music is being able to make very long patterns out of much shorter rulesets. However with this representation, to find the 10,000th event you’d have to calculate the 9,999 events preceeding it. This becomes a particular problem when modifying these structures as part of a live coded musical improvisation.

Instead of explicitly representing a recursive structure, I’m now hiding everything inside a function mapping from integers to a list. You pass the function the current position in the pattern (e.g. the current ‘beat’, and get back the list of events at that position. For certain operations you still need to know the period (length) of the repeating pattern, so that’s in the datatype constructor too.

What kind of operations can I do to these patterns? Here’s one that simply shifts events backwards in time:

… which shifts the pattern back in time two steps, but only affects every other group of 4 steps.

This is probably fairly humdrum stuff, but quite fascinating to me as someone relatively new to both haskell and functional programming. Being able to pile functions on top of functions in this way lets me compose complex patterns out of simple parts, and I only ever have to deal with the simple parts in memory, not the complex patterns. Great! Thanks to the parameterisation of the Pattern datatype, I can also use patterns for different aspects of a rhythm, my recent screencasts [1,2] showing concurrent patterning of samples, vowel formant filtering, sample playback speed and a comb filter.

I’ve also been looking at making the Pattern a Monad (my first ever monad instance, woo!):

Where ‘combine’ is another function not shown that which merges patterns together. The problem I’m having with this is that functions of type a -> Pattern a for use with >>= can’t do that much, not being able to consider any pattern context, and not being able to return a different period depending on the input (otherwise that ‘undefined’ value would bite). This is about the most useful thing I can come up with, which ‘masks’ events every other time measure:

Maybe I should be thinking of what I could do with more general functions of type (a -> Pattern b) instead. I guess I’m just getting a better handle on what monads are really for…

Monads aside I guess my Pattern representation would really become unstuck with patterns that have a lot of interdependencies. For example if every event depended on the event preceding it then you’d have to recalculate the whole pattern all the time. Hmm.

Well that was quite an extended haskell wibble. If by some strange chance you’ve read this far I’d love to hear your thoughts and especially advice!

11 thoughts on “Patterns in Haskell”

It, and its precurser, HMSL (Hierarchical Music Specification Language) tackle a some of the ideas you’re working with. It’s clear you’re having a lot of fun leaning functional programming and digging around in haskell, and I think that’s a great way to go. You might want to take a look at some of the ideas in HMSL/JMSL just to see how other people worked through some of this stuff in a different world.

HMSL was written in Forth! It was the first language I really did any music with. dupswapdrop. Most of Larry Polansky’s music is HMSL/JMSL-based. Plus JMSL now makes it easy to crank out traditionally notated scores, which can be really nice.

Sorry about the formatting, the operator used in Applicative is <*>. Also, I realized that “fxs” doesn’t quite typecheck, but if you replace ($) with <*>, you get a definition that does!

Also, you may want to look at the Reactive library; I am seeing some striking similarities between what you are defining and that library. There’s a paper about the library here: http://conal.net/papers/push-pull-frp/

A function of type
a -> Pattern b
doesn’t really make sense, since it would consume anything, and produce a pattern of some other, totally unrelated type. Also not everything needs to be made into a monad (since not everything is one), you can combine things in other ways too. That said, good luck and have fun using Haskell to make music :) This might be of interest to you: http://www.haskell.org/haskore/

… although at the moment I’m not sure what that buys me. Much to read!

I’ll have a go at Conal’s paper for sure Ryan, interesting that what I’m trying to do is somehow related to FRP, I had no idea.

Good point about a -> Pattern b being useless leadnose. I was thinking of functions from some particular type to some other particular type, rather than to the same type, but of course they’d have a less general signature than that. After too long programming perl, this is all still coming together in my head…

Hi Alex. Your patterns remind me of FRP also. The two representations are akin to syntax (algebraic data-type) & semantics. I think you’ve done what I often like to do as well, which is to program directly with denotations rather than data structures.

There is a hazard in using functions as your representation that took me many years to grok. Ironically, functional programming is biased against functions and in favor of data structures, in that data structures are automatically memoized, while functions are not.

I don’t like your applicative instance (it is similar to the applicative instance for zip-lists); I think the applicative instance for regular lists makes more sense. The difference is that [(+1),(+2)] [3,4], for regular lists is [4,5,5,6], but for ziplists is [4,6]. Still, I can see how you might want to go that direction.

However, you also give special treatment to the “f” argument; if it’s short, the resulting list gets cycled, but if the “x” argument is short, it doesn’t. I am pretty sure that violates one of the applicative functor laws. (f <*> pure x = pure ($x) <*> f).

Ints made sense to me as a representation of ‘score time’. A series of slots where things can go. To get ‘performance time’ e.g. swing, I add floating point offsets to that. I have to think more on this though, looking forward to learning more about FRP.

I went for what you point out is ziplist-like behaviour so I could effect particular ‘levels’ in a polymetric pattern. I think that should probably be done in a more explicit way though. I’ll respond to your blog post properly soon Ryan.