Show HN: “Statements and State”, the next chapter of my book on interpreters
craftinginterpreters.com
craftinginterpreters.com
There are so many great books out there on how to create a lisp, or a typical mutable object-oriented language, but with one notable exception (that's unfinished), there are no approachable online tutorials/books out there that I've found on building compilers or interpreters for functional languages. Only academic papers, a textbook, and one or two books from 20-30 years ago.
Pierce's Types and Programming Languages is a great textbook that covers all of this material, but from an extremely detailed and formal academic perspective. It would be great to see more approachable tutorials or short books online to complement Pierce's text.
I've started writing my own in-depth tutorial on this subject using Scala as the implementation language, but would love to see other tutorials/books as well.
I'm interested in that too. I've heard good things about Appel's book [1], but haven't read it yet.
> There are so many great books out there on how to create a lisp, or a typical mutable object-oriented language
For what it's worth, I haven't found much about creating object-oriented languages. There's a lot on Lispy dynamicall-typed languages, but I haven't seen much on things like method dispatch, vtables, inheritance, etc.
One of the reasons I'm writing this book is to try to cover that. Even if you don't like OOP languages, I think it's worth knowing more about how they work under the hood since they are so prevalent in the industry.
> I've started writing my own in-depth tutorial on this subject using Scala as the implementation language
Interesting! Is it online yet?
Appel's other compiler book, "Compiling with Continuations", goes into more depth while falling short of being a complete tutorial on writing a compiler for ML.
Another similar read is Vidar Hokstad's blog series - Writing a compiler in Ruby [1] which was first submitted here 9 years ago! [2]
Of course in addition to executing an AST you can also generate CODE for it...
Yes! In the third part of the book [1], we'll do exactly that. The C interpreter's parser generates bytecode as it parses. I haven't written the text yet (that's the hard part...) but you can see the code for it here [2].
[1]: http://www.craftinginterpreters.com/a-bytecode-virtual-machi...
[2]: https://github.com/munificent/craftinginterpreters/blob/mast...
My impression (for better or worse) is that few people use RSS these days, so it didn't seem like a great use of my time to get it set up.
If you don't want to join the mailing list for whatever reason (though it is quite low traffic), you could follow me on twitter too (@munificentbob). I tweet whenever a new chapter is up.
Personally I've found that RSS is more popular than ever, especially in the tech space as the number of news sources available these days is so large partly due to the number of individual blogs out there and services like feedly along with wonderful apps like reeder.
Yes, I hand-rolled a little build script tailored specifically to the book.
Otherwise, I'd spend countless hours tinkering with frameworks and libraries and never actually write the damn book.
Also, to enforce an extra layer of learning, I am writing the interpreter in Go. (book uses Java and C)
https://github.com/pravj/glox
The "satisfactory" part is, I've started applying the learning to other problems (writing a transpiler, completely different from the book's context), despite being in the middle of the book.That's a very interesting approach. Is that something you usually do when learning, or you just wanted to use Go for this? Anything else you can say about the practice?
I feel that dynamic variable lookup is a mistake, though -- it's just so painful to have to wait until runtime to discover you've made a typo. Is supporting mutual recursion really important enough to offset this pain?
function f() { g() }
f()
var x = read_user_input()
function g() { print x }
Static languages typically don't allow the calls to f() and read_user_input() -- maybe that's the right answer here. There are other answers that come to mind as well. But, either way, I don't think we should perpetuate the mistake of dynamic variable lookup. let rec even n =
match n with
| 0 -> true
| x -> odd (x-1)
and odd n =
match n with
| 0 -> false
| x -> even (x-1)
Although personally I've never liked the idiom where everything at the top-level is a statement. Even in OCaml I usually define a 'main' function, and call it at the bottom of the file: let main args = do stuff...
...
let () = main Sys.argv> Although personally I've never liked the idiom where everything at the top-level is a statement.
For statically-typed languages, I'm not a huge fan of it either. But for dynamically-typed ones, I think it works out OK.
I do think supporting mutual recursion is very important. People expect it to simply work, especially in an object-oriented language. It does work out of the box in JavaScript, Python, Ruby, and Lua. (And note that also none of those will detect access to undefined variables until runtime.)
Early versions of my main hobby language Wren did detect this error statically but it ended up interacting poorly with the REPL and I became convinced it didn't provide enough value to justify the static checking.
The main thing that tipped the scales for me was that Scheme works this way. That seems like a pretty reasonable path to follow for a dynamically typed language.
I should probably link to it from the site...
https://github.com/munificent/craftinginterpreters/blob/mast...
It's more complex than the build script[1] for my previous book[2], but still pretty simple. There's a real luxury in writing a program that literally only has to run on one single set of input data. A whole lot of things get easier.
[1]: https://github.com/munificent/game-programming-patterns/blob...
A very simple example of political speak: Merkel basically said last Sunday: "We can't trust our overseas partners anymore. I've seen that the last few days. We must take our fate in our own hands."
Yet what she meant was: "Trump will let you down. I'm strong enough to defy him. If you want a strong leader that listens, come to me."
Another example is how the G7 fought just about phrasing of a final statement for day and night before. What does the result mean? Who won what? How will that influence decision of other people in the political landscape?
Really curious to learn about that.