______________________

                                                 RPN CALCULATOR REDUX

                                                                 lro
                                                ______________________


                                                       <2019-01-03 Thu>


Table of Contents
_________________

Stuff we can re-use
Values
Push
dup
factorial
rpn-func macro
Main loop
conclusion


In my last phlog, I wrote a simple RPN calculator in scheme, but even
though it wasn't particularly "functional", the stack was a global
variable that we modified in place. Not good form a functional point of
view. So lets rewrite our calculator to be more functional. It can't
really be purely functional because scheme isn't purely functional
itself. But we can make our best effort to be as functional as possible.


Stuff we can re-use
===================

 We can't keep alot of our old implementation, we just have to change
 the functions that alter the stack to return the altered stack
 instead, and also take the stack as an argument.

 Like /pop!/ use to just alter the stack using /set!/, but insetad
 /pop/ will take the stack as its argument and return the popped
 variable and the stack.

 ,----
 | (define (pop stack)
 |   (let ((var (car stack))
 |             (ret-stack (cdr stack)))
 |     (values var ret-stack)))
 `----

 I could have just one-linered this but its easier to see what is going
 on if i use a /let/ and name the return values nicely.


Values
======

 If you know how multiple return values work in scheme, then you can
 skip this section.  But otherwise here we go!

 You can do multiple return values in scheme several ways, the easiest
 is probably to build a list and return the list where each element is
 one of the return values.

 ,----
 | (define (pop stack)
 |   (let ((var (car stack))
 |             (ret-stack (cdr stack)))
 |     (list var ret-stack)))
 `----

 But when accessing each variable, it requires some list dancing to
 access but is my personal usual way of handling multiple return
 values, but i'm choosing to go with /values/ this time because I
 haven't used it before.

 And the third is continuation passing style, which is strange
 looking. You return a function acting on your return variables that
 was passed to your function.

 ,----
 | (define (pop stack func)
 |   (let ((var (car stack))
 |             (ret-stack (cdr stack)))
 |     (func var ret-stack)))
 `----

 So this time around I've chosen to go with /values/.


Push
====

 Pushing values onto to stack is pretty much the same, we just return
 the modified stack and thats it.

 ,----
 | (define (push var stack)
 |   (append (list var) stack))
 `----


dup
===

 dup duplicates the last item on the stack, and is again similar to
 /push/ where all we do is take the stack as an argument and return it
 again.

 ,----
 | (define (dup stack)
 |   (let ((head (car stack)))
 |     (append (list head) stack)))
 `----


factorial
=========

 Factorial is exactly the same.

 ,----
 | (define (fact x)
 |   (define (fact-iter n current)
 |     (if (= n 1)
 |       current
 |       (fact-iter (- n 1) (* n current))))
 |   (fact-iter x 1))
 `----


rpn-func macro
==============

 We will have to change this macro so that it returns the stack and
 also uses the new /pop/ and /push/. I will also change it just a
 function because it's not really a good use for a macro.

 So you can see I used /let*-values/ to capture the return values of
 popping the stack twice, and because we used /let*-values/ instead of
 /let-values/, we can use the previous varibles so that the modified
 stack can be passed to the next /pop/.

 ,----
 | (define (rpn-func func stack)
 |   (let*-values (((var1 stack) (pop stack))
 |                             ((var2 stack) (pop stack)))
 |     (push (func var1 var2) stack)))
 `----


Main loop
=========

 The main loop doesn't need too much changing, but there are some
 things we need to change.
 1. Initial call to loop needs another variable, the stack.
 2. change all the /rpn-func/ calls to use the stack.
 3. change the implementation of modulo, factorial etc
 4. change $ to use /let-values/ to display the top element of the
    stack then return.

 The only problem is how do we get what is returned form the /cond/ to
 our loop invocation.  One way is to have every expression in the cond
 call /loop/, but that seems ugly to me. If I find a better solution
 later I will phlog about it.

 ,----
 | (let loop ((input (read)) (stack '()))
 |   (cond
 |    ((number? input) (loop (read) (push input stack)))
 |    ((eq? '+ input) (loop (read) (rpn-func + stack)))
 |    ((eq? '- input) (loop (read) (rpn-func - stack)))
 |    ((eq? '* input) (loop (read) (rpn-func * stack)))
 |    ((eq? '/ input) (loop (read) (rpn-func / stack)))
 |    ((eq? '% input) (loop (read) (rpn-func modulo stack)))
 |    ((eq? '! input) (loop (read)
 |                                              (let-values (((var stack) (pop stack)))
 |                                                (push (fact var) stack))))
 |    ;;((eq? '^ input) (loop (read) (rpn-func pow)))
 |    ((eq? '$ input) (loop (read)
 |                                              (let-values (((var stack) (pop stack)))
 |                                                (display var)
 |                                                (newline)
 |                                                stack)))
 |    ((eq? 'dup input) (loop (read) (dup stack)))
 |    (else (begin
 |                (display "ERROR not valid input: ")
 |                (display input)
 |                (newline)
 |                (loop (read) stack)))))
 `----


conclusion
==========

 So there we are, a mostly more functional RPN calculator, though there
 is still some more improvements that can be made.