Vessel - Writing a Game in Elm
This week at Hacker School I started working with a language called Elm. The language’s creator (Evan Czaplicki) was a resident during the week so I had the absolute best resource available to me while playing with it. The language is functional (based on Haskell, or so I’m told) and features Functional Reactive Programming, among other things. In other words, Elm would throw a lot of new concepts at my imperative brain.
Initially progress was slow. At the end of the first day all I had to show was a program that wouldn’t compile. I made some gains the next day by talking to fellow students who were familiar with functional concepts and eventually paired with Evan for about an hour which helped immensely (special thanks to Brian as well - check out his Elm flappy bird clone). The end result was a “tunnel” type game much like the one that I used to play on my TI-83+ graphing calculator in high school. In all it took me about three days to go from zero knowledge to small functioning game.
Elm’s most distinguishing feature is Functional Reactive Programming. The general idea is that you can bring in variables that change (or don’t) over time. For example, the mouse’s
y coordinates can be represented by the
Mouse.position signal. As a user moves their mouse, its coordinate is pushed through the program. When these signals are pushed (that’s probably not the best term) can be controlled by a function called
sampleOn. At every sample the functions invoked by
foldp get to work and begin to “update” the game state (I say update but what I really mean is a new state is created based on the existing state - it’s immutable).
foldp function was difficult for me to grasp initially. This function is similiar to
foldr functions, but works over
Signal inputs. My mental model of this concept is to imagine
Signal inputs as an array, where only the first value is accessible. This value represented the latest “signal.” Eventually I came to understand that the “p” in
foldp stands for “past” which helped it make more sense. It probably didn’t help that I was unfamiliar with the other “fold” functions as well and had to learn those too.
I began to start thinking functionally towards the end. This meant making sure each function had all the information needed via its args to do its job and thinking in terms of composing functions together rather than passing objects by reference into functions. In other languages you can get a way with modifying a global variable in a function without taking the time to refactor, eliminating referential transparency, and potentially introducing bugs in the future as complexity increases.