24 comments

[ 3.2 ms ] story [ 43.4 ms ] thread
Given how this is about building and compiling programming languages a portrait of Admiral Grace Hopper would have been more appropriate than Ada Lovelace.
Or Jean Sammet (author of a very comprehensive book on programming languages in the 1960s), or Lois Haibt (involved in development of original Fortran compiler) or Frances Allen (did key work at IBM on optimization in Fortran compilers), or Sister Mary Keller (involved in developing Dartmouth Basic), or Adele Goldberg (key developer of Smalltalk), or Barbara Liskov (CLU, and many other things)...those off the top of my head, though a web search would find many more, I'm sure.
i’m grateful to the author for making their work available online for free.

i once did an exercise like this myself (just the code not the book) for fun and found it extremely gratifying even though the code does not survive and never made it into any of my other projects as i had hoped at the outset.

mine got to be around 5 kloc with all the error handling but i wasn’t optimizing for keeping it short. i’m impressed by the many super brief ones that others with deeper understanding have built.

the point of view that this is really about learning C might have been buttressed further by starting with an existing super brief personal lisp and reading through that in a structured way; something that i personally would still like to do and that i semi-resorted to when debugging my way through the eval of the y-combinator which was one of the moments that exposed my poor design choices and the flaws i wasn’t cognizant of when doing simple expression evaluation. building a proper test harness was also a big deal as i went which seems like a highly relevant bit to highlight in a journey like this.

some references to existing high-quality short personal lisps and schemes might also be a welcome addition.

I may be old. But use to use the pure Lisp Chatlin included in C with his papers to learn languages a few times.

Not as complete as this version of the language, but apparently ~300 lines of even REXX was enough although I never tried REXX.

This is MUCH more than a 'Build Your Own Lisp'. To the point of almost being anything but.

This is an amazing resource for getting started with learning C by making your own "programming language", independent of any Lisp conventions.

For me, the most 'lispy' aspect of 'making your own lisp' is prebaked by the author with their using their own prebuilt parser library 'mpc'. (I was unable to find a link to the source in the book, so https://github.com/orangeduck/mpc )

I was unable to find any instance of 'car' or 'cdr' or 'caddar' and their like, which I feel is the real 'build your own lisp' epiphany.

https://en.wikipedia.org/wiki/CAR_and_CDR

The parser is so widely, and wildly, useful that it is independent of notation style, for instance, lisp's nearly ubiquitous 'polish notation'. (or its variants, for instance, 'cambridge polish notation')

Perfect example:

Under 'Chapter 9: Reading Expressions':

> Don't Lisps use Cons cells?

> Other Lisps have a slightly different definition of what an S-Expression is. In most other Lisps S-Expressions are defined inductively as either an atom such as a symbol of number, or two other S-Expressions joined, or cons, together.

> This naturally leads to an implementation using linked lists, a different data structure to the one we are using. I choose to represent S-Expressions as a variable sized array in this book for the purposes of simplicity, but it is important to be aware that the official definition, and typical implementation are both subtly different.

https://www.buildyourownlisp.com/chapter9_s_expressions#Read...

This is an awesome educational resource.

I think I would promote it more broadly than "Build Your Own Lisp".

Like most of these tutorials, this stops right where things get interesting. Taill-Call Optimization, Continuations, CPS, Call/CC... those are the things that are tricky to implement and without those the language is only a toy language.

Then again, creating a toy-language is a worthwhile goal in itself, so kudos to everyone who follows this through to the end

Don’t Build Your Own Lisp: https://gist.github.com/no-defun-allowed/7e3e238c959e27d4919...

Just so people are aware of it. It is not a good source if you want to learn how to make a lisp that could scale beyond a toy.

You can still learn a bit of C and get a taster of how to make a language, just be aware that some stuff you learn will hold you back in the long term.

He makes many good points in his criticism but I'm still wondering what language one's supposed to use if not C.

My lisp has a conservative mark-and-sweep garbage collector. The mark phase spills all registers and then walks the entire stack looking for pointers to lisp objects. I managed to implement the stack walking through some convoluted pointer nonsense but even C could not express the notion of spilling registers, I had to write assembly code for each architecture.

I have no idea how such a garbage collector would be implemented in Rust or Zig.

Here's a more balanced take:

"Build Your Own Lisp" is an opinionated, idiosyncratic take on one style of programming in C and one way to implement a Lisp-like language.

If you go into it treating it like an intro textbook to the "standard" way of implementing an interpreter, it may lead you astray. Worse, it may lead you astray without realizing it if it's your first book on the topic.

On the other hand, if you approach it as following an author as they deliberately wander off the well-trod path of implementing Lisps with recursive descent and all the other classic techniques, then you can have a good time and maybe get some interesting ideas out of it.

For what it's worth, I quite enjoyed the book. But I had enough programming language experience already to know when the author was teaching you the basics versus teaching you their own thing.

The more the world world becomes aggregated, summarized, averaged, and watered down, the more I crave stuff like this that is quirky and unique.

This is a solid take. I also had the same opinion on the book. You're better off doing the Norvig Lisp in Python journey then branching out on your own.
>> In our Lisp, when we re-assign a name we’re going to delete the old association and create a new one. This gives the illusion that the thing assigned to that name has changed, and is mutable, but in fact we have deleted the old thing and assigned it a new thing.

> Please don’t do that. What would be the result of evaluating:

  (let ((a 1))
    (+ (let ((a 2)) a) a))
That is off the mark; that example doesn't re-assign anything; it is binding a shadowing instance of a.

Removing a binding and destructively creating a new one in the same environment is a viable strategy for implementing assignment, compared to mutating just the value part while keeping the same binding cell.

You can implement it so that the semantics is absolutely identical; the program simply cannot tell.

If you try to make it nondestructive somehow, then the program can tell; e.g. if you functionally rewrite the current environment to produce a new environment in which the variable is edited to the new value. then closures will reveal the trick. Previously captured closures keep seeing the old environment and old value (obviously inapplicable discussion to dynamic scope).

If a variable that has been captured by any number of closures is destructively assigned, all the closures must see the new value after the assignment, otherwise you have something other than assignment.

Are there any such build-a-lisp books/guides using modern c++?
Is there a resource which compares Lisps (expressiveness, limitations, available special forms, ...)? I often read about lisp 1 and 2.0, clojure being a lisp 1.5 (because of the callable keywords if iirc).

Dabbling into llms I think that lisps could be very interesting format to expose tools to llms, ie prompting a llm to craft programs in a Lisp and then processing (by that I mean parsing, correcting, analyzing and evaluating the programs) those programs within the system to achieve the user's goal.

> lisp 1 and 2.0

Do you mean Lisp-1 and Lisp-2 as in the number of namespaces?

https://dreamsongs.com/Separation.html - Goes into depth on the topic including pros and cons of each in the context of Common Lisp standardization at the time (ultimately arguing in favor of Lisp-2 for Common Lisp on grounds of practicality, but not arguing strictly for either in the future).

Common Lisp was a, more or less, unification of the various Lisps, not Scheme, that had developed along some path starting from Lisp 1.5 (some more direct than others). They were all Lisp-2s because they all kept the same Lisp 1.5 separation between functions and values. Scheme is a Lisp-1, meaning it unifies the namespaces. The two main differences you'll find are that in CL (and related Lisps) you'll need to use `funcall` where in Scheme you can directly use a function in the head position of an s-expr:

  (let ((f ...))     ;; something evaluating to a function
    (f ...))         ;; Scheme
    (funcall f ...)) ;; Lisp
Related:

Build Your Own Lisp - https://news.ycombinator.com/item?id=36103946 - May 2023 (12 comments)

Learn C and build your own Lisp (2014) - https://news.ycombinator.com/item?id=35726033 - April 2023 (45 comments)

Learn C and build your own Lisp (2014) - https://news.ycombinator.com/item?id=27598424 - June 2021 (86 comments)

Learn C and Build Your Own Lisp (2014) - https://news.ycombinator.com/item?id=17478489 - July 2018 (86 comments)

Learn C and build your own Lisp - https://news.ycombinator.com/item?id=10474717 - Oct 2015 (49 comments)

Learn C and build your own Lisp - https://news.ycombinator.com/item?id=7530427 - April 2014 (145 comments)

I learned recently that the creator of the Iosevka typeface did so using their own Lisp implementation.

The typeface:

https://github.com/be5invis/Iosevka

The language:

https://github.com/be5invis/PatEL

Their tool which they used to build the language:

https://github.com/be5invis/patrisika

These kinds of projects are deeply inspirational. Striving to achieve one percent of this output would be enough for me. Knowing there are people like Belleve / Renzhi Li and their team in the world -- that I might be able to do something like what they do if I, too, try hard -- is what makes me get out of bed in the morning. It is incredible that there are people like them, doing what they do, and sharing it freely. Thank you so much.

PS: Re: inspo: Hope 16 is next week :D https://www.hope.net/pdf/hope_16_schedule.pdf

As others have pointed out, this is as much about learning C as it is about making a Lisp.

If you're interested in the latter, Peter Norvig has a little project that builds a stripped down Scheme interpreter in python. Takes some shortcuts, provides only a few functions (about 30) to its environment and only recognizes 5 special forms (`quote`, `if`, `define`, `set!`, and `lambda`) but the whole thing is less than 150 lines and very informative if you're new to that kind of thing.

https://norvig.com/lispy.html

It seems to use c99, I would like to know from folks who have read this book, for learning newer features in C, what do you recommend?

Also, does this book also teach some of the pitfalls of stdlib like gets or scanf?

Basically I always read in HN/lobsters/other forums that modern C is just as safe as newer languages but I don’t see much book or tutorials teaching modern concepts or even industry standards like Misra?

I highly recommend writing your own Lisp interpreter in any language followed by writing a Lisp compiler using your own interpreted Lisp (compiling to C for example).

It is great fun!