
Writing a Lisp: Explicit Stack and Stacktraces - reinvdwoerd
http://reinvanderwoerd.nl/blog/2017/05/11/writing-a-lisp-explicit-stack-and-stacktraces/
======
rrmm
I feel like writing a LISP in a gc'ed language is taking away most of the fun
of it. I wrote one in C (without a conservative garbage collector) and the
most interesting aspect was what had to be done to allow garbage collection.

Garbage collection can run inside nearly all subroutines. So any temporary
references stored outside of the heap need to be kept track of at all times.
If gc occurs you have to able to walk the entire heap _and_ the entire
callstack to mark live data. This is obvious but I enjoyed finding it out (and
subsequently rewriting everything).

~~~
marcpaq
The irony of implementing Lisp in assembly is that, almost for free (sorry
about that), you get precise, convenient control of the memory situation. Just
put the gc root exclusively in registers.

I wrote a Lisp interpreter in assembly that dedicates 4-5 registers for the
current expression, eval environment, and so on. The mark-sweep collector
starts from these registers.

[https://github.com/marcpaq/arpilisp](https://github.com/marcpaq/arpilisp)

~~~
kazinator
No irony there. You need precise control over the machine to implement a
paradigm accurately from the ground up. It's hard to do that using someone
else's paradigm, living with their choices of what aspects of the machine are
still revealed and which are hidden.

------
penpapersw
Back when I wanted to write a Lisp interpreter, I thought Haskell would be one
of the best languages for it because of its type system. But looking at this
code, although I'm sure it's probably very good, it just doesn't strike me as
very intuitive or readable. Is this something you get used to over time, like
reading Lisp code? Or is it just inherently harder for non-mathematically-
minded people to read?

~~~
gavinpc
I had the same reaction. The only part of this that I could read was a little
surprising:

    
    
        pop :: CallstackIO ()
        pop =
          modify popFrame
          where popFrame (_:xs) =
                  xs
                popFrame xs =
                  xs
    

Not that it's very onerous to implement, but I would expect these "pop"
semantics to be imported from some more general type (or trait, or whatever
Haskell uses for type composition). That said, I don't know what `modify`
means.

~~~
reinvdwoerd
From the documentation:

"Maps an old state to a new state inside a state monad. The old state is
thrown away."

[https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-M...](https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-
Monad-State-Lazy.html)

------
mbil
I've been writing my own lisp (in Clojure) by following the make-a-lisp[0]
process guide. So far it's been challenging and interesting. It gives clear
direction without being too hand-holdy.

[0] [https://github.com/kanaka/mal](https://github.com/kanaka/mal)

