__________________

                                                       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.