Climbing the Elm Tree
The selection of the second language of the month was mired in confusion; there was one language I had had in mind, and I spent the week after the previous blog post learning more about it. However, I then learned a new release was in the pipeline for April, so it seemed natural to delay my adventures with that language for two months.
I then picked another language to work on, but it occurred to me that it was already February 22nd. That's what four birthdays in the family, a late start, and preparing for a talk will do to you! I didn't want to shortchange this new language by giving it a paltry one week of my time, so I decided to defer my time with that language until March.
The language I ended up writing about for February is one I actually played with a bit in 2015 (sorry for cheating!), but it still represents a paradigm shift in how one writes code, and I've never blogged about it before, which is an injustice itself! It's gotten a lot of press lately, so you may have heard of it - it's the Elm programming language!
A gateway to functional programming
Functional Reactive Programming
The big takeaway from Elm is how it treats functional reactive programming
(FRP) as its core concept. Like other functional languages, such as Haskell,
functions in Elm are pure - that is, they have no side effects 2).
If you want to express side effects, you typically use signals, which
represent a stream of events in your program, such as inputs. If you want to
render HTML or draw on a canvas, your
main function needs to return an
Element object, or a
Signal of them. This may seem pretty
strict, but it inspires a natural architecture in your application that is easy
to read and reason about. Code in Elm is so clean; it's the most excited
about a language I've been in a long time. Here's a simple example code
snippet that displays the timestamp once per second:
main : Signal Element main = Signal.map show <| Time.every Time.second
Signals offer many list-like functions, such as
map, which applies a function every time
a new value comes in from a signal, and treats the results of the function as a new signal.
show simply renders a value for debugging purposes, and
Time.every n creates a signal
that yields the current timestamp every
n units of time. For a deeper look into how signals
make an Elm program work, check out the official
Working with Elm has inspired me to think about ways of applying FRP concepts in other languages, especially Perl 6!
Time Traveling Debugger
Not only does the strictness of Elm yield cleaner programs, but it also allows for advanced tooling. The Elm platform ships with a tool called elm-reactor, which is a little web server that will allow you to edit your programs and have your changes loaded on the fly in the browser. Where it really shines is the debugger, though; elm-reactor provides a time traveling debugger. This means if you find a bug, you can back up the program state to what it was just before the bug happened. After you've done this, you can set up watches, logging statements, or fixes in the code, and replay the execution. You can find a demo of the time traveling debugger here.
Bad Error Messages as Bugs
One of the things that put Elm on the map for many people is that in the 0.16 release, the error messages were considerably improved. The Elm team seems to have the mentality that an error message that confuses or misleads a user is a bug, and that the compiler is your assistant. The Rust community has also seemed to embrace this idea, and I'm hoping that other language communities do as well. It's definitely something I keep in mind now when I'm working on Perl 6!
Tune in next time for an overview of the program I wrote in Elm, which makes use of the data I gathered in my previous blog post!