Since the text adventure is my first attempt at making a relatively complex piece of software in Haskell, I’ve learned a lot about what it’s like to develop using the language. I thought I’d share my thoughts about a few of the things I learned.
Developing in Haskell is fast
I estimated that I would take about three weeks just to get the natural language parser finished and it took about two weeks to get the entire project completed. I’m astonished by how little code I had to write to get this working. This is really amazing because I can now imagine doing projects in Haskell which I would never have dreamed of tackling on my own in another language. I don’t have to spend as much of my own free time to get a project done.
It doesn’t just work the first time it compiles
There is a myth about Haskell that if you can get it to compile, it just works. This is just not true. I had to go through several iterations of compile-and-test to get the software working just like in any other language I’ve worked with.
Making changes is surprisingly easy
I made some late-breaking changes to my design, like adding more grammar, adding support for an inventory and flags. Although it took a significant amount of work to support these, it was far less work than it would have been in any other language I code in. I think the reason for this is that it’s very easy to go from supporting a single object to supporting a list of objects of the same type.
The type system is here to help
At one point while coding the narrative graph, I was concerned about mixing up inventory items with flags, which were both represented by Strings. I decided to make a type for each of them just to enforce at compile time that they couldn’t get mixed up. I could have done this in any other language of course, but the burden of adding two extra types with static checking in other languages I know would have been higher. I really appreciated being able to add the constraint with minimal changes to the existing code.
Haskell encourages you to write domain specific languages (DSLs)
When I started working on this text adventure, I didn’t intend to make it general. I just wanted to write one hard-coded specific adventure. It became evident after writing the lexer that it was almost no effort to make the engine support any kind of text adventure, so I split the lexer, parser, and narrative graph out into modules. Over the course of the project, I started making more and more types and syntax specific to text adventures and I ended up with something like a DSL for text adventures. It seems to me that I was naturally drawn to writing declarative DSLs to solve problems in Haskell. I’ll cover what my text adventure DSL looks like in a later post.
Sometimes things can become too concise
Coming from an imperative programming background, I really didn’t think it was possible to make code which is too concise; but I’ve discovered that I was wrong. Once you start thinking with higher order programming techniques, you start to write code which looks like random strings of characters like “>>= fmap <*> pure <$>”. This kind of code is powerful and often it could take dozens of lines to write an alternative to a clever line of code which uses higher order functions. The downside is that, in my opinion, this kind of code is less readable and maintainable.
It has become very tempting to use higher order functions everywhere because I end up writing less. I’m sure this will be a trade-off that I’ll have to balance in the future.