Wow. So many hours spent on this project. Read this blog post for some insight into the process.
Here are some words about the start of the whole thing. Initially, I was just intrigued by the idea of capturing the entire syntax description of core IMP in Haskell, just like on the lecture slides. That was pretty easy and fun. Then, I asked AI to write a simple parser. That was really easy too - it was baffling how compactly this could be done with some library support. Finally, I wanted to be able to execute statements parsed into the IR data types. Again, this was quite straightforward. Pretty much just pattern matching on the inference rules from the lecture and implementing them.
From then on, I was hooked. Wanting to add as many extensions as possible forced me to change the state data type frequently. Adding new parse rules was always the easiest part, though. At some point, it occurred to me to also implement small-step semantics. For convenience, it was obvious I