__________________ SQUASH THAT BUG! lro __________________ <2019-01-10 Thu> Table of Contents _________________ Control flow .. equal .. If .. do loop fix complex number bug R7RS compatability Conclusion Control flow ============ Initially I wasn't going to add control flow abilities, but I think we need a simple if statement and a looping construct. equal ~~~~~ Tests if the top two elements of the stack are the same, using schemes /eq?/ ,---- | (cons '= (lambda (stack dict) (rpn-func eq? 2 stack))) `---- If ~~ If the stack head of the stack is true (#t) then execute next function otherwise execute function after that one. I chose to only execute one function because i thought it would make the implementation much simpler. ,---- | (cons 'if (lambda (stack dict) | (let*-values (((var stack) (pop stack))) | (if var | (let ((ret-stack (run-func (read) dict stack))) | (read) | ret-stack) | (begin | (read) | (run-func (read) dict stack))))) `---- do loop ~~~~~~~ Repeat a function until the head of the stack is equal to the second number on the stack. ,---- | (cons 'do (lambda (stack dict) | (let loop ((stack stack) | (func (read))) | (let ((head (car stack)) | (second (cadr stack))) | (if (= head second) | (let*-values (((var stack) (pop stack)) | ((var stack) (pop stack))) | stack) | (let ((stack (run-func func dict stack))) | (loop (run-func 'inc dict stack) func))))))) `---- I needed a nice little function for incrementing as well. ,---- | (inc 1 +) `---- And those will be all the control flow constructs that we need, more can be created by using user functions. fix complex number bug ====================== So it turns out that that bug doesn't appear when I use gerbil scheme's interpreter with R7RS language option, so it might be a bug in chibi-scheme, I will try with the HEAD of chibi-scheme's git repo, not the 0.8 release. Just tried the latest HEAD of the chibi-scheme git repo, yeah it still happens. However after trying the same function in chicken scheme's interpreter, it yielded the correct result. Very strange. But it behaves strangely, the chicken interpreter (v4.12) also does the same thing where it only reads one function invocation per line and only prints one thing at a time, unlike chibi-scheme which I have been testing on. It seems to mostly happen with the $ operator. Tried chicken-scheme v5 with the r7rs egg and it performs the quadratic calculation correctly, but still doesn't like the $ or D operator. I think chibi-schemes handling of /read/ and handling of complex numbers differs from both gerbil and chicken scheme. Both gerbil and chicken look like this: ,---- | ; loading rpn-calc.scm ... | 1 1 1 quadratic-eqn | $ $ | -0.5-0.866025403784439i | 1 | -0.5+0.866025403784439i `---- The second $ only prints after I do another operation on the stack, in this case push a 1. I've tried adding /flush-output-port/ to various spots, to the definition of $ and D, and the start of the main loop, but to no avail. More experimentation has led me to the fact that gerbil doesn't execute the last function when it reads, until you enter more stuff in next time. I can write a a hacky workaround so that every time you manually type into the command line just type the END operator and it'll be a dummy operator that does nothing but return the stack. ,---- | ;; add to init-dict | (cons 'END (lambda (stack dict) stack)) `---- It works but I would rather not keep it permanantly. It seems like gerbil has this off-by-one sort of error when I /read/ in the main loop. R7RS compatability ================== I just want to take a moment to mention some scheme implementations and their differences when running this program. I've mostly been using chibi-scheme to test this code, which works perfectly except for the complex number bug. Where as both gerbil and chicken scheme (with their respective r7rs libraries) fail in the same ways. 1. The if function we defined doesn't work if the result of = is true 2. And still the weird output when displaying. Here's an example of number one. ,---- | 1 1 1 0 = if + - D END | (1 1) | D END | (2) | ;; WTF??? why does it print (1 1) when the satck should be (2)?? | ;; AND THEN WHY IS IT NOT (0)??? | $ END | 2 | ;; now stack is empty | 1 1 1 1 = if + - D END | | Error: (car) bad argument type: () `---- Maybe I'm getting tripped up by the r7rs spec just leaving the order of evaluation for arguments up to the implementation? Because chibi-scheme strictly does right-to-left evaluation, maybe chicken and gerbil left-to-right? or unspecified? What I'm going to try is moving the input in the main loop to be that last arg for /loop/. HOLY FUCK THAT ACTUALLY FIXED IT. Now when I run it in chicken scheme or gerbil it works PERFECTLY. And now chibi-scheme bugs out the same as chicken and gerbil did. Fuckin' hell. So that means that both gerbil and chicken evaluate left-to-right. Confirmed. So to have it work the same in all the schemes, I could use the /delay/ and /force/ lazy evaluation primitives, to delay the /read/ call until we are in the loop. And after testing that works, fuck yeah. Conclusion ========== So this time it turned into a whole bunch of bug hunting, and getting royally bit by the scheme spec. But its not so bad, the fix was pretty trivial. Next time we will FINALLY get around to some macros and more RPN programming. If you have any features you would like to see feel free to email me. Thanks.