Okay, so I went ahead and wimped out and did an easy one because I'm behind. Perl's a language I already know well, and I did basically a straight-up port of the Pike version. They turn out to be very similar languages! There are some interesting points of comparison between them.
Notes about Perl and/or Pike
Perl's syntax in a few places shows serious age or poor foresight. For example, Python and Pike both support open-ended array-slices: array[1..] to take all but the first element in a functional manner. In Perl, that's array[1..$#array]. Also, I don't know what they were thinking with the particular style of sigil syntax used in Perl. I.e., if you have an array named @foo, you can have a scalar named $foo, and $foo[0] refers to the first element of the array, and @foo[0, 1] refers to the first two. The sigils are selected based on the type of the expression, not of the variable. This gets disastrous when it comes time to indirect through references. Mind you, references in Perl are their own disaster; they make explicit what every other language (save I guess C) properly makes implicit, resulting in a lot of wasted keystrokes.
Perl's map function gets a nice syntactic boost from the $_ global, the "universal default". In places like map where a proper language would take a lambda, Perl instead takes a block and passes the argument in $_. This is theoretically impure as sin, but it's nice to have a syntax for "the implicit single parameter of this obviously-single-parameter block", and you could easily do it in a nice lexical way if you wanted to. (For bonus points: The one case where the block takes two parameters, namely the sort function, Perl uses $a and $b to pass the parameters, which also exist as magic globals for this reason alone. This I support ... ... less.)
Of course, perl's map function also loses because you can't pass it a function; you can _only_ pass a block. So map foo bar becomes map { foo($_) } bar.
I implemented algebraic datatypes in perl using the bless facility, which was designed for classes but whatever. It lets you tag a reference with a string (and, if there exists a package named with that string, lets you call methods on the reference and looks them up in that package. This part I did not use.) This was a mixed, er, blessing. You can't pattern-match on bless tags, but that didn't increase verbosity much beyond the Pike level.
More general notes:
Why doesn't any language seem to have a 'multimap' function, which maps over N lists in parallel? I guess the typed languages don't have it because you can't type it without at least dependent types (and I think you also need list kinds if you want it to be heterogeneous), and the non-lisp languages probably because they just don't like that kind of higher-order nonsense anyway. But why doesn't lisp have it? (I bet it does, and I just don't know where it is.) Something like this would be ideal in the functions-on-blocks-pretend-to-be-syntax languages, a-la:
for list1, list2, list3 {|x1, x2, x3|
return {foo: x1, bar: x2, baz: x3};
};
It would be like a super-duper-zip.
I've mentioned this in previous posts, but I have trouble stating forcefully enough the importance of including debugging aids in language infrastructure. Logging should be built-in. Tracing (i.e. at the least being able to log, if not execute arbitrary code, on function calls/returns) should be built-in. Error signalling of some kind (exceptions or "die" or what have you) should be built-in. For the love of god, backtraces on error reporting should be built-in. A stringification operator should be built-in (who cares if it's a shitty one, for debugging purposes any unambiguous representation will be fine.)
Bugs I discovered in the previous version while writing this version: Forgot to evaluate the exp in "(define exp)". Oops. Also put a period where I needed an arrow. I think the fact that this wasn't an error leads me to a principle of language design: The more denser your syntax (and hence the higher the probability that any stupid thing will fail to be a syntax error), the more you need types for protection against stupid things that fail to be syntax errors.
Interesting implementation fact about this interpreter: Since none of my primitive functions actually require the context, I forgot to pass it to them. This means I couldn't write set. Since the setq builtin sort of obsoletes the set primitive, I just left it out...
Code:
here.
Next: I don't even
I pretty much banged this one out at top speed to try to reduce my behinditude, but it is still about three days. I'm not sure if I should do a legit one next, or another fast one, but whatever it is, I'd better start it quick.