Lists and Lists (1996)
eblong.com
eblong.com
Totally got sucked in, and an hour or so later I had finished. Accounting for all those parens was really frustrating at first, but with the help of a good editor I eventually feel like I got into the "Lisp headspace."
I have played around with Haskell a bit. Scheme feels more verbose, but also closer to the metal^H^H^H^H^Hlambda calculus. The feature I missed the most was currying:
>>(define sum (foldr + 0))
[Error: too few arguments to function]
You can get around this somewhat: ; manually implement currying on a per-arity basis
(define curry2 (lambda (f)
(lambda (arg1) (lambda (arg2)
(f arg1 arg2)))
))
(define curry3 (lambda (f)
(lambda (arg1) (lambda (arg2) (lambda (arg3)
(f arg1 arg2 arg3))))
))
; now define a curried foldr:
(define cfoldr (curry3 foldr))
; and finally:
(define sum ((cfoldr +) 0))
The dynamic typing was also a bit foreign for me, so it took a while for me to wrap my head around "megasum." I can vaguely imagine how to implement it in Haskell, but it wouldn't be pretty! data Sexp = Int Int | Nil | Cons Sexp Sexp
megasum Nil = 0
megasum (Int i) = i
megasum (Cons l r) = megasum l + megasum rEven this solution is not completely equivalent to Lisp megasum -- it fails to compile on the list `('a)` ;-)
Some notes:
- Source code: http://eblong.com/zarf/ftp/lists.tar.Z
- The Scheme engine that this implements is really small -- about 10k of heap. (This is a Z-code game, and the Z-machine is a 16-bit architecture.) And the garbage collection sucks. So you can't do much with this beyond toy problems.
- You could port it to the Glulx VM (32-bit architecture) without too much trouble, and then you'd have a couple of gigabytes. Feel free. :)
- As an IF author, I never intend players to guess a verb. But I do expect players to be familiar with the common IF verbs -- the stuff on the PDF sheet, basically. This was more true in 1996, when the IF community was tiny and all read the same Usenet group. I wrote this thing for enthusiasts.
- Today, I'd put more emphasis in the help docs on the difference between the two input modes (">" and ">>"). And I'd check if the player typed a line starting with ">" -- display an appropriate explanation of why that's wrong.
- But I'm not going to update this thing, because yes, 1996 was a long time ago.
- The era of the text adventure is dead the way the era of home-brewed beer is dead. Nobody makes it and nobody drinks it, except the people who still do.
- Is it silly to write a text adventure in 2014? I put one up for sale a couple of months ago (hadeanlands.com) and it's doing pretty well. Yes, for actual money. No, it's not a gigantic indie success, but the niche still exists and there are still fans. So that's my past twenty years of work justified.
You push the door open. It doesn't creak at all.
>enter
White Room This is a comfortably cluttered room. Cluttered with bookshelves, mostly. To one side is a large desk, on which a computer squats regally. A lumpy couch is the only other furniture of note.
Beside the computer is a small glass box.
Resting on the couch, and snoring in a manner which you suspect infringes copyrights owned by several local earthquakes, is a huge genie. Honest.
>eat the genie (first taking the genie) I don't suppose the genie would care for that.
>eat the computer (first taking the computer) That's hardly portable.
>eat the glass box (first taking the small glass box) That's plainly inedible.
>eat all the books You can't use multiple objects with that verb.
Lisp is historically less concerned with not exposing implementation details than more modern language traditions. The attitude is: the hacker might need it, throw it in! For example, the ability to compare pointers directly (rather than some expensive traverse-the-whole-datastructure comparison) makes it possible to implement hash-consing, a clever optimization technique.
(It's also no more of an abstraction leak than, say, Python's "is" operator.)
This is a funny comment, because "refusing to leak abstractions" is the most famous reason for why Lisp never became broadly popular, in one of the most famous stories in all of computing: http://en.wikipedia.org/wiki/Worse_is_better
Exposing implementation details is also not quite the same thing as a leaky abstraction (although they can coincide). eqv? can be both, if you regard "cons" as an abstraction of a mathematical pair. OTOH, if you regard cons as allocating a mutable pair object, then it is neither.
Providing a function to trigger garbage collection is exposing an implementation detail, but not leaking abstraction.
It's harder to come up with examples of leaky abstractions that don't in some sense expose implementation details. I'm not sure they exist.
>help
"Do this:
>>(define twentyseven 27)
>>(define twentyseven 27)
That's not a verb I recognise.
>help
"I really can't get any more explicit."