
Lisp interpreter in 90 lines of C++ - fogus
http://howtowriteaprogram.blogspot.com/2010/11/lisp-interpreter-in-90-lines-of-c.html
======
shin_lao
I'm both a Lisp and a C++ fan and I really like the idea, but I'd like to make
a couple of suggestions.

\- Use the STL algorithms more. There are way too many "for" loops in this
code which are trivial std::accumulate or std::transform calls.

\- When I see the eval and tokenize functions I ask myself, why not use
Boost.Spirit.Qi?

\- I'm not sure working on a list of strings is efficient, why not work on a
list of pairs of pointers instead?

\- Use smart pointers to avoid leaks.

Just a small contribution, I really like the idea.

~~~
nocman
"I'm both a Lisp and a C++ fan..."

I find that to be very interesting. I spent far too many years working with
C++, trying to master all of its nooks and crannies. It was my frustration
with the limits of the language that drove me to finally learn Lisp. The fact
that for loops always ended up appearing _clearer_ than using STL was
extremely frustrating. I'm not 100% sure that the introduction of lambdas in
the newer versions of the C++ standard will _not_ fix the problem (or at least
help some), but I sincerely doubt that they will be enough. I truly _wanted_
to use STL and the the standard containers, but it always ended up feeling
like I was working extra hard to try and "get it right". In the end it was
faster just to grumble, write another for loop with an explicit iterator, and
move on.

And yes, I'm aware of Boost and the like. I have all the template
metaprogramming books you are likely to name. It all still feels terribly
unnatural and forced compared to, say, composing a chain of function calls
against a list of data in Lisp or Scheme.

~~~
shin_lao
I really like playing with Racket. It's very powerful and simple.
Mathematical. I concede that. But it's not "natural". I can guarantee you that
Lisp showed to a novice isn't "natural".

C++ is different. It's not unnatural. There's no "natural" programming
language.

C++ is explicit. You need to manage your memory. You need to tell how the
return value will be handled. You need to work with the compiler, the linker.

You have more control. More power. It gets in the way for some tasks, but it
is mandatory for others.

I find the lack of STL to be frustrating, because I'm used to it. To me it
feels "natural".

There's no problem with not being proficient with C++ or the STL. It's just
not your thing!

~~~
nocman
Just to be clear, I didn't describe Lisp as "natural", I described using the
STL (meaning, particularly, heavy use of STL algorithms, function objects,
etc) as feeling terribly unnatural and forced. Judging by the reaction here,
"unnatural" was perhaps not the best choice of words. What I meant was this:
when trying to use the STL to get stuff done, I felt like I was always jumping
through hoops to do things "the STL way", with the end result being more
complicated and less clear than just doing it in a "C++ without the STL" way.

> I can guarantee you that Lisp showed to a novice isn't "natural".

Again, I never argued that Lisp was "natural". And secondly, if you are
dealing with a true novice (as in, someone who has never programmed in any
programming language), both C++ and Lisp are going to look decidedly
"unnatural" to them. But I don't want to beat the natural/unnatural language
dead horse any longer, since that was not what I was discussing. However, I
will concede that Lisp looks decidedly foreign to people who _have_ programmed
before in languages with an Algol-like syntax (C, C++, Java, Javascript, Perl,
etc).

And, for the record, I am _very_ proficient in C++ (many years of work
experience), and I understand how the STL works very well (I invested a _lot_
of time in learning the STL). I invested that time because I wanted to make
C++ do more than it had done for me in the past, and the STL seemed like the
way to do that. However, in the end I decided that there really was no good
way to make C++ do what I wanted, and the real answer was to go with something
that was far better at handling higher level constructs. After trying out Lisp
(and Scheme) for I while I realized that the primary things I was trying to do
with the STL were no-brainers in Lisp. And with a decent FFI I can still use C
or C++ when I need to do things at a lower level. I still use C++ libraries
when it makes sense to do so, but I would not now start a new project with C++
as the primary language if given the choice to use something else (unless, of
course, the only choices were something even worse than C++ :-D ).

------
spacemanaki
> Nevertheless, I get a little thrill out of having made something that allows
> me to type (define cube (lambda (n) (* n n n))) and then (cube 3). It's like
> magic.

This is great, and it's really true. I've just finished the Metacircular
chapter of SICP and felt the same way after reading their code and doing some
of the exercises. I think "90 lines of C++" is kind of a silly goal (just
because LOC is silly) but it's still a great learning experience. I'd love to
try a non-metacircular evaluator after I've read more SICP.

The author might be interested in <http://michaux.ca/articles/scheme-from-
scratch-introduction>

I think I found that on HN somewhere, it's been in my TOREAD for a while.

~~~
hvs
If you're interested in getting into the details of implementing a Lisp/Scheme
interpreter and compiler, I highly recommend Lisp in Small Pieces:
[http://www.amazon.com/Lisp-Small-Pieces-Christian-
Queinnec/d...](http://www.amazon.com/Lisp-Small-Pieces-Christian-
Queinnec/dp/0521545668)

~~~
sedachv
mahmud turned me onto Abdulaziz Ghuloum's An Incremental Approach to Compiler
Construction: <http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf> ; I can't
stop raving about it.

------
dtf
I have to say I'm a huge fan of these "X in 100 lines of C++" adventures.
They're a great starting point for people like me wanting to learn about a
subject in a programmatic way.

This global illumination ray-tracer was posted a while back:
<http://kevinbeason.com/smallpt/>

~~~
silentbicycle
Here's one of the most interesting "X in Y lines of Z" programs I've seen, a
prototype interpreter for the basics of an APL-like language in one page of
(rather funky, Arthur Whitney-style) C: <http://nsl.com/papers/origins.htm>

It segfaults due to nonportable assumptions about pointer sizes in the
allocator, and is far from complete as APLs go, but I spent a couple hours
picking it apart and came away quite impressed.

There's a similar raytracer (<http://nsl.com/k/ray/rayq.k>) in 17 lines of Q,
but I haven't figured that one out yet.

------
olalonde
> // Scheme Interpreter in 90 lines of C++ (not counting lines after the first
> 90).

It's actually 333 lines.

~~~
kleiba
Wait, did you count the lines after the first 90?

~~~
mooism2
Yeah, I didn't count the words after the first C++.

------
lisper
A similar thing, but with better integration with C++. Includes exceptions and
a full numerical tower:

<https://github.com/rongarret/Ciel>

Note: not quite ready for prime time. Just a proof of concept for now.

------
fogus
I am also a sucker for "X in Y lines of Z code" posts. I would love to see a
comprehensive list arranged by language/topic.

------
agazso
I'm nitpicking, but actually any C or C++ program can be written in one line,
but otherwise it's a great experiment.

~~~
pmiller2
I threatened to do this in an introductory undergrad systems programming
course I had to take to satisfy a degree requirement in spite of it being way
below my level of proficiency. Fortunately for my grade and the grader's
sanity, I chose not to do it.

~~~
scott_s
If your grader was aware of the indent program, it wouldn't be an issue.

~~~
swolchok
Graders at the University of Michigan are willfully unaware of it because we
want students to have _some_ coding style. You'd be surprised how many have to
be repeatedly slapped around until they get a real programmer's editor instead
of trying to use gedit without configuring it.

------
wrs
I know this is a curmudgeonly thing to say, but I'm happy to see one of these
"implementing Lisp" articles where someone started with a _lower_ -level
language than Lisp. It just seems like you miss out on a lot of interesting
learning if you start with something like Ruby or Python that is so close to
Lisp already.

For example, implementing lambda with a Python lambda...really? You are
missing a giant a-ha moment there, as you can see from this article.

Note: implementing a metacircular interpreter for Lisp in Lisp is a beautiful
special case exception to my curmudgeonliness.

------
deadsy
I looked at the Norvig lis.py code and took the time to understand every line.
It's a clever program and taught me a few new Python tricks. The main reason
he can get it down to so few lines of code is that he leans back on the
capabilities of Python. E.g. garbage collection, arbitrary objects stored in
hierarchical lists, lambdas, use of dictionaries for the environment/symbol
table. If you try the same thing with a language like C you either need
library support or more lines of original code.

------
zitterbewegung
Why do people keep on calling lisp-1's scheme? This doesn't even have call/cc
... its basically scheme in name only.

------
johnohara
Tried to compile this using Borland's C++ 5.5 (free). The only function not
supported was 'isdigit()'. Wrote a simple version just for fun and it
compiled.

I was able to run the first example completely.

Not bad for an out-of-date but free compiler with a 1993,2000 copyright.

------
eschulte
Lisp interpreter in 4 lines of Clojure! <https://gist.github.com/720413>

Sorry I know this is rude, but I'm tired of seeing so many posts about lisp
interpreters in high level languages, the vast majority of which don't mention
macros -- the only plausible reason that such an interpreter would really be
useful (mine does support macros :)).

