______________________

						  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.