Building a tool in Haskell for dynamical systems research.
Over the years since FractalStream was first released, there have been several instances where people wanted to use FractalStream on Windows; unfortunately, the original program was written to target OS X and is heavily entwined with Objective C and Apple’s Cocoa framework. I did some experiments to try to get it to build under GnuSTEP and the Cocotron, but never did end up with a reliable and stable build.
Another sticky point is the LLVM dependency. I really like the LLVM project and their clean, well-thought-through APIs. But the downside is that to get these nice APIs, you have to be willing to make breaking changes. The effect is that people have not had terrific luck getting the right LLVM dependency in place so that FractalStream will compile, even on OS X.
So how am I planning on solving these problems to get a FractalStream that is cross-platform, maintainable, and can be hacked on by anybody anytime?
Would you believe me if I said “by using a language whose motto is ‘avoid success at all costs’”?
That language is Haskell, a purely functional language in the ML family. Maybe it isn’t surprising that a mathematician writing mathematical software would choose Haskell: it’s family tree leads back to the language used to compose proof tactics in the early automated theorem prover LCF (1972).
Haskell has made many design choices that seem foreign to many programmers but natural to mathematicians:
All variables are immutable; just a name attached to a value. No “x = x + 1” funny business.
Functions are considered values. You can pass around and manipulate functions just as easily as you pass around and manipulate integers.
All values in a Haskell program are typed, but the programmer doesn’t need to explicitly declare types except in very exceptional cases or for documentation purposes.
Evaluation is lazy. Haskell will only evaluate enough of an expression to get the final result.
Although I have used Haskell for some scripting tasks and some rapid prototyping, I have never had the chance to try it out on the scale of a medium-sized application like FractalStream. But from my experience so far, there are several points in Haskell’s favor.
Haskell is fun to work with, especially if you are coming from a mathematical background. Haskell code has monoids and functors and F-algebras and all kinds of cool gadgets from algebra and category theory. Since I’m doing this as a hobby project, being fun is probably design criteria #1.
The Haskell community is excellent. Since many members of the Haskell community are active researchers in type theory and programming language design, Haskell is curated by people who care deeply about getting things right. In other words, the Haskell motto is really “avoid [success at all costs]”, not “[avoid success] at all costs”.
Much of the work on Haskell is supported by papers, which I have found to be generally quite lucid. Read anything by Simon Peyton-Jones and you’ll see what I mean.
For questions, the #haskell IRC channel is very active and very useful.
Haskell is high-level, memory safe, and garbage collected. FractalStream involves a lot of fiddly low-level operations like allocating rendering buffers, drawing results into pixel buffers, compiling scripts to executable code, multithreading the script execution, and so on. Keeping this all working properly in Objective C (or regular C, or C++) was a mess. Haskell offers a higher level of abstraction and far more stringent guarantees about program execution, which should make managing the low-level details safer, easier, and more correct.
Haskell has a good refactoring story. As I built the original FractalStream, design mistakes were inevitably made. At first, it was easy enough to refactor the design to keep things clean. But as the project grew, it became calcified: making changes to the overall design or interface of any particular component became increasingly difficult. By contrast, Haskell offers a strong type system that can be used to guide a program’s refactoring. The type system even encourages better design from the start by forcing implicit assumptions about code behavior to be reified in the types.
Haskell is cross-platform and actively developed by an open community. The Haskell ecosystem is great on Linux and OS X, and pretty decent on Windows. There are even Haskell compilers which target the browser by compiling to Javascript. The de facto Haskell compiler ghc
is mature yet still improving rapidly, acting both as a stable platform and as a testbed for programming language research.
Haskell has good library support and C integration. The Haskell FFI makes it easy to interface with C libraries, and many useful library wrappers already exist for the components that FractalStream requires: LLVM and/or OpenCL, GUI libraries, language parsing, and so on.