4 ms·
Things I see... 1. Mac OS apparently has a conflicting definition of "isnumber", as "__DARWIN_CTYPE_TOP_inline int isnumber(int _c)" in "/usr/include/ctype.h:3
by waterhouse 8y ago
Things I see...
1. Mac OS apparently has a conflicting definition of "isnumber", as "__DARWIN_CTYPE_TOP_inline int isnumber(int _c)" in "/usr/include/ctype.h:323". Thanks, Mac OS. So I'm running this on another machine of mine.
2. My usual test: iteration expressed as anonymous recursion, which should be possible to run in constant space:
pi@raspberrypi:~/LISP $ echo '
((lambda (f) (f f 10 0))
(lambda (f n tt)
(cond ((equal? n 0) tt)
(#t (f f (- n 1) (+ n tt))))))' | ./komplott
55
pi@raspberrypi:~/LISP $ echo '
((lambda (f) (f f 100 0))
(lambda (f n tt)
(cond ((equal? n 0) tt)
(#t (f f (- n 1) (+ n tt))))))' | ./komplott
5050
pi@raspberrypi:~/LISP $ echo '
((lambda (f) (f f 1000 0))
(lambda (f n tt)
(cond ((equal? n 0) tt)
(#t (f f (- n 1) (+ n tt))))))' | ./komplott
Out of memory
Aborted
I noticed from the source that eval did recursive calls to itself. I expected that to be its bane, but I'm surprised it hit an OOM rather than a stack overflow... It looks like, in lisp_eval's "apply" case, it'll call gc_protect on all the relevant stuff, then only do gc_pop after everything returns; perhaps that's why.
In the absence of other looping constructs, looping by tail recursion seems the best available option, and therefore an important usage to support. Implementing that, along with a moving GC, in a language that doesn't do its own tail call elimination is a pain.
- krig 8y agoYeah the TCO is not complete, it allocates a call frame for each call regardless which is why it ran out of memory. It doesn’t use up the C call stack though, so you could in theory increase the GC heap size to make it survive longer. Due to the primitive environment implementation it’ll get slower and slower as it goes. Thanks for the note on Mac OS, I’ll fix that.