lsys - A L-system implementation in Haskell

A L-system, short for Lindenmayer-system, is a mathematical formalism to describe the behaviour of plant cells and to model the growth process of plant development.

For a long time, I was aware of the book "The Algorithmic Beauty of Plants" [ABOP], written by Przemyslaw Prusinkiewicz and Aristid Lindenmayer, but never found the time to study it. I was aware that this book is a real classic in computer science. Maybe I heard of it when I was at university. Now, some decades later, I remembered my desire to read the book. I started looking for a print version in good condition. Eventually, I found one. It was expensive but completely worth the money.

lsys is my modest take on writing an L-system interpreter in Haskell. Find it on codeberg.org/bwolf/lsys.

It implements the following input symbols for the axiom and production rules: F, f, -, +, [, ] and ε.

It takes as input an L-system definition, which is a simple file format that describes the relevant aspects of the system. It looks like this:


n: 5
d: 90
axiom: L
p: L->+RF-LFL-FR+
p: R->-LF+RFR+FL-
    
Example L-system: a Hilbert curve

Here, n is the number of iterations, d is the rotation angle, and axiom is the start configuration, which gets rewritten in each iteration by the production rules denoted byp.

This is used to drive turtle graphics (well known from [Logo]), where the turtle initially looks straight up. When a rotation command + or - is read, the turtle is rotated by the angle delta (d). A draw command is an upper-case letter, which moves the turtle by some unit, resulting in a line being drawn. A move command works similarly with lower-case letters.
Stack commands are [ and ]. The former pushes the turtle state onto the stack, the latter pops the turtle state from the stack.
The ε symbol is supported in production rules to state that a symbol should be replaced by nothing.

All parameters of a system (like the number of iterations) can be overridden via command line arguments.

For coloring the drawings, a few simple methods are implemented: by index, distance, height and default. Default is the simplest, which only takes the foreground and background color into account. The other methods produce, for a line, an palette index which is used to index a perceptually uniform color map.

Examples

Koch

Definition
n: 2
d: 90
axiom: F - F - F - F
p: F -> F - F + F + F F - F - F + F 
    
Colors: cetI1, Method: index
Title

Koch island dense

Definition
n: 4
d: 90
axiom: F-F-F-F
p: F->F-FF--F-F 
    
Colors: cetC1, Method: index
Title

Quadratic snowflake

Definition
n: 4
d: 90
axiom: -F
p: F->F+F-F-F+F 
    
Title

Sierpiński gasket

Definition
n: 6
d: 60
axiom: R
p: F->R+F+R
p: R->F-R-F 
    
Title

Bracketed edge rewriting a

Definition
n: 5
d: 25.7
axiom: F
p: F->F[+F]F[-F]F 
    
Colors: cetL10, Method: distance
Title

Bracketed edge rewriting b

Definition
n: 5
d: 20
axiom: F
p: F->F[+F]F[-F][F] 
    
Colors: cetL19, Method: distance
Title

Bracketed edge rewriting c

Definition
n:4
d:22.5
axiom:F
p:F->FF-[-F+F+F]+[+F-F-F] 
    
Colors: cetI2, Method: distance
Title

Bracketed node rewriting d

Definition
n:7
d:20
axiom:X
p:X->F[+X]F[-X]+X
p:F->FF 
    
Colors: cetCbl2, Method: distance
Title

Bracketed node rewriting e

Definition
n:7
d:25.7
axiom:X
p:X->F[+X][-X]FX
p:F->FF 
    
Colors: cetL08, Method: distance
Title

Bracketed node rewriting f

Definition
n:5
d:22.5
axiom:X
p:X->F-[[X]+X]+F[+FX]-X
p:F->FF 
    
Colors: cetD10, Method: distance
Title

Dragon curve

Definition
n: 10
d: 90
axiom: F
p: F->F+R+
p: R->-F-R 
    
Colors: cetL17, Method: index
Title

Hexagonal gosper curve

Definition
n: 5
d: 60
axiom: F
p:F->F+R++R-F--FF-R+
p:R->-F+RR++R+F--F-R 
    
Colors: cetL12, Method: index
Title

Hilbert

Definition
n: 5
d: 90
axiom: L
p: L->+RF-LFL-FR+
p: R->-LF+RFR+FL- 
    
Colors: cetC1, Method: index
Title

Penrose

Definition
n: 4
d: 36
axiom: [N]++[N]++[N]++[N]++[N]
p: M->OF++PF----NF[-OF----MF]++
p: N->+OF--PF[---MF--NF]+
p: O->-MF++NF[+++OF++PF]-
p: P->--OF++++MF[+PF++++NF]--NF
p: F->ε 
    
Colors: cetL10, Method: height
Title

Copyright © 2026 M. Geiger