Elm – fun with L-System (Part 1)

You can become a serverless blackbelt. Enrol in my course Learn you some Lambda best practice for great good! and learn best practices for performance, cost, security, resilience, observability and scalability. By the end of this course, you should be able to make informed decisions on which AWS service to use with Lambda and how to build highly scalable, resilient and cost efficient serverless applications.

Friday was my last day at Gamesys, bringing to an end a wonderful 6 years I’ve enjoyed at the company. Seeing as I’m starting my new job at JustEat in November, so for the first time in almost 10 years I have time on my hands to relax and go through my backlog of TODOs.

One of those outstanding TODOs was to check out L-System, which I’ve been fascinated about ever since I read this post by Mathias Brandewinder.

 

I wanted to try out the same examples in Elm, which is another hobby of mine.

Why?

Because it has this awesome time-travelling debugger, which I can use to see how the different examples grow frame by frame and then even go back and forth!

 

Series:

  1. Algae (this)
  2. Pythagoras Tree
  3. Cantor Dust
  4. Koch Curve
  5. Sierpinski Triangle
  6. Dragon Curve
  7. Fractal Plant

 

As the wikipedia page for L-System contains quite a few different examples, I’ll go through the implementation for each in Elm over a few posts.

To start nice and easy, let’s look at the Algae example.

 

Modelling a L-System

Since there’s no drawing involved, this example allows us to focus on modelling a L-System with types.

image

As you can see, my approach here is almost identical to Mathias’s, with the exception that Symbol is a type alias for Char rather than a union type of its own right.

Why?

Mostly because you can’t use a union type as key in a Dict in Elm. But also because I find it simplifies consuming code in this case, whilst a type alias still allows me to surface my domain through types.

Personally I’ve used both approaches and make my choice based on the chance of getting it wrong (or, what additional type safety buys me) and the amount of effort involved.

p.s. Scott Wlashcin wrote a nice piece about the 2 approaches from a performance point-of-view, which I also recommend you reading.

 

Then we just need a way to “evolve” a state based on the rules of a L-System:

image

Since Dict.get returns a Maybe,  we have to provide a default value – the symbol itself in this case – if the symbol is not found in the rules.

To evolve the L-System to a given generation, we can just use simple recursion:

image

 

Modelling the Signals

For the demos, I want to be able to go from generation to generation using the arrows keys.

e.g. starting with gen 0, -> moves to gen 1, -> again moves to gen 2. But if you press <- then you move back to gen 1, and so on.

To do that, we need to capture the arrow key presses, and use the x value (see mapping below) to “change” the current generation.

image

Starting with gen 0 (the axiom), we’ll fold over the signal of integer values (either -1 for LEFT, or +1 for RIGHT), whilst capping the output value at 0 (hence the max 0 at the end).

image

Finally, we’ll map this signal of generation numbers into a signal of states by evolving the L-System to the specified generation:

image

 

All the code we’ve seen above are put inside a Core module that all the other examples will share.

 

Example 1 : Algae

So now we can finally look at one of the L-System examples. Once the Core module is in place, there’s actually not much to be done here.

We still need to define the L-System for Algae:

image

but since there’s nothing to be drawn on the screen, we’ll just keep things simple and display the output (list of Char) as a string instead:

image

 

Live Demo (here)

Remember, use LEFT and RIGHT arrow keys to evolve/devolve the L-System.

 

Source Code (here)

 

Next : Pythagoras Tree

 

Links

Liked this article? Support me on Patreon and get direct help from me via a private Slack channel or 1-2-1 mentoring.
Subscribe to my newsletter


Hi, I’m Yan. I’m an AWS Serverless Hero and the author of Production-Ready Serverless.

I specialise in rapidly transitioning teams to serverless and building production-ready services on AWS.

Are you struggling with serverless or need guidance on best practices? Do you want someone to review your architecture and help you avoid costly mistakes down the line? Whatever the case, I’m here to help.

Hire me.


Check out my new podcast Real-World Serverless where I talk with engineers who are building amazing things with serverless technologies and discuss the real-world use cases and challenges they face. If you’re interested in what people are actually doing with serverless and what it’s really like to be working with serverless day-to-day, then this is the podcast for you.


Check out my new course, Learn you some Lambda best practice for great good! In this course, you will learn best practices for working with AWS Lambda in terms of performance, cost, security, scalability, resilience and observability. We will also cover latest features from re:Invent 2019 such as Provisioned Concurrency and Lambda Destinations. Enrol now and start learning!


Check out my video course, Complete Guide to AWS Step Functions. In this course, we’ll cover everything you need to know to use AWS Step Functions service effectively. There is something for everyone from beginners to more advanced users looking for design patterns and best practices. Enrol now and start learning!


Are you working with Serverless and looking for expert training to level-up your skills? Or are you looking for a solid foundation to start from? Look no further, register for my Production-Ready Serverless workshop to learn how to build production-grade Serverless applications!

Find a workshop near you