Day 2 language: Haskell!
I wanted to save the languages I know well for days when I am really pressed for time. I figured Haskell would be a happy medium -- I knew bits and pieces of it going in, and figured I could pick it up quickly since it's a lot like SML.
I used
Learn You A Haskell For Great Good to get up to speed on the basics, and poked around in it for topics like creating typeclass instances.
I was excited to take advantage of lazy evaluation in one place: In the evaluation of a recursive function definition, instead of backpatching -- which I can't do because no mutation -- I evaluate the definition in the context that includes the result of evaluating the definition. Thanks, Haskell! Thaskell.
I committed the semi-cardinal sin of using unsafePerformIO to write debug output, and I actually found it quite instructive! I got to watch lazy evaluation in action, as Haskell first skipped my (object-language) function definition and tried to evaluate its application. Then in the middle of trying to print the environment of the application, it suddenly jumped back and started evaluating the definition! So unsafe debug IO was both more and less useful than I expected.
I discovered several deficiencies in my Day 1 interpreter, in the process of writing this one. It lacked recursive functions (as mentioned already, oops), conditionals (oops), equality testing (oops), and math on the numeric values (oops).
Today's interpreter, by contrast, lacks mutable state. Since Haskell is pure, but I fear monads, I tried to avoid using them by threading the environment through everything by hand. I realized far too late that this is not sufficient for mutable closures; some sort of more-clever heap-threading would be required, tracking closure environments with some sort of gensym'ed token, and looking them up with another layer of indirection, to allow replacing them on the fly during closure execution.
Or I could have just learned to use monads.
Still haven't written a parser (but I did say I didn't have to.) Hope to do that at least once before the end of the month.
I ended up having to search for two major bugs in Day 2 before 'fact' worked: I forgot to evaluate the arguments in function application (holy shit, d'oh), and I was missing primes on the variables being compared in do_eq. Despite the catastrophe that unsafePeformIO-based tracing produced, it was instrumental in finding both (and in fact, the fact that I didn't see Haskell trying to evaluate the arguments to eq was what led me to notice that I wasn't actually using the results of the evaluation, due to my typo.)
Find the source
here. (Check that directory for yesterday's source, too, and my Git repo (in a hidden .git directory).)
Tomorrow: Pike, perhaps?
EDIT: I've added links in my profile to the intro post and the list of languages. I'm keeping the list of languages updated as I go along.