This one is a cheat because read does a lot of the work. I can tolerate treating STDIN/OUT as black boxes because they often are. The Scheme interpreter's functionality is what's custom. The read function is crucial to it. So, it's implementation should be included. That puts this way over 7 lines.
The good news is that I now know where the name Y Combinator comes from. I imagine it will take me a lot longer to wrap my head around that concept, though. Truly weird haha.
Eh, "implement X in Y lines" for Y < 10 is pretty much always a cheat. At least this cheat has solid computer science behind it; most such cheats boil down to "import library; library.cheat()", or, for the particular "implement a programming language", JavaScript "eval".
It was one of many from the link below. The Scheme in Racket example would've been even easier to specify concretely because it's so easy to implement read in a Scheme. Gets the C and C++ implementations more props for doing things directly. Real question is how small can those go?
Reminds me of the tale of the two programmers arguing. One says "Mine actually works right." The other retorts, "But mine runs faster!" The first merely sighs.
Building almost nothing and using a very, high-level language definitely helps keep line count low. I wonder if we should count the runtime in these very-HLL examples. One like PreScheme, a system variant, I'd probably not count the runtime although might count the running time. :)
That's a trip. Reminds me of when I studied and toyed with AI programs. The first books I learned taught LISP, Prolog, and mixing the two. We'd normally implement Prolog in LISP. Allegro still does. Neat to see it done the other way.
Want a fun project? Run this one through a Prolog compiler and create some LISP benchmarks. Then, recode it in the Mercury language, which IIRC is No 1 logic language, then see how that code performs (and looks). Should be straight-forward and enlightening for those interested in logic programming.
Even the classic lisp eval that fits in a page, puts aside cons (aka gc). It's funny how different the problem they were describing was to put away memory as an implementation detail.
Beside the theoretical side of Y, what made it interesting to me was the few tutorials on how one could derive it to stop an infinite expansion, which is a feeling I often get when trying to solve a problem, creates another similar problem only slightly different. Now I stop and try to find how to make bind the tail to the dog's mouth.
To be clear: the Y combinator is just one way to define a fixed-point combinator in the untyped lambda calculus. You can define fixed-point combinators differently and achieve the same effect.
I do agree that the realization that it's possible to build recursive functions in the lambda calculus is mind-blowing (and far from obvious!)
The brief description I saw and sltkr's comment look like gibberish to me. Not enough math or FP background I guess. I think learning it is probably going to be part of a larger, mind-altering effort for me when I eventually dig deep into FP to understand it. Lambda calculus, too, while I'm at it.
The good news is that I now know where the name Y Combinator comes from. I imagine it will take me a lot longer to wrap my head around that concept, though. Truly weird haha.