________________

                                                        RPN CALCULATOR

                                                                 lro
                                                       ________________


                                                       <2019-01-02 Wed>


Table of Contents
_________________

Introduction
How I think it works
The Stack
Main Loop
Calculator Functions
factorial function





Introduction
============

 A common exercise for prorgramming is to implement a [Reverse Polish
 Notation] calculator, usually just with a commandline interface.

 I have never actually done this exercise before. So here is my first
 attempt in R7RS scheme.


[Reverse Polish Notation]
https://en.wikipedia.org/wiki/Reverse_Polish_notation


How I think it works
====================

 A simple way to implement an RPN calculator is to use a stack, and
 push each value onto the stack, then operate on the stack when you hit
 an operator like `+' or `/'.  If you are familiar with Forth then this
 will sound pretty familiar.


The Stack
=========

 So first we will define our stack, we will just use a list at the
 moment, and each new element of the stack will be pushed onto the head
 of the list.

 ,----
 | (define *stack* '())
 `----

 Probably best to define the basic stack operations like /pop!/ and
 /push!/.

 ,----
 | (define (pop!)
 |   (let ((ret (car *stack*)))
 |     (set! *stack* (cdr *stack*))
 |     ret))
 |
 | (define (push! val)
 |   (set! *stack* (append (list val) *stack*)))
 |
 | (define (dup!)
 |   (set! *stack* (append (list (car *stack*)) *stack*)))
 `----


Main Loop
=========

 The main loop will consist of:
 1. Wait for input from standard input.
 2. Read each token in and check if either a number or an operator.
 3. If operator, do operation.
 4. If number, push onto stack.

 I have used a named let to loop through the standad input using
 /read/, then each which kind of acts like a tokenizer where it returns
 each scheme object for us from standard input. As you can see it is
 trivially easy to add more functions too this calculator by just
 adding a clause to the /cond/ by adding some syntax, and writing a new
 function that just has to interact with the stack.

 ,----
 | (let loop ((input (read)))
 |   (display "RPN> ")
 |   (cond
 |    ((number? input) (push! input))
 |    ((eq? '+ input) (rpn-add))
 |    ((eq? '- input) (rpn-sub))
 |    ((eq? '* input) (rpn-mult))
 |    ((eq? '/ input) (rpn-div))
 |    ((eq? '% input) (rpn-mod))
 |    ((eq? '! input) (push! (fact (pop!))))
 |    ((eq? '. input) (begin
 |                                      (display (pop!))
 |                                      (newline)))
 |    ((eq? 'dup input) (dup!))
 |    (else (begin
 |                (display "ERROR not valid input: ")
 |                (display input)
 |                (newline))))
 |   (loop (read)))
 `----


Calculator Functions
====================

 So as you can probably guess all the /rpn-*/ functions are just
 wrappers of scheme functions that get there arguments from the stack
 and their return values are pushed back onto it.

 For example addition:

 ,----
 | (define (rpn-add)
 |   (push! (+ (pop!) (pop!))))
 `----

 We could write a macro that expanded from something like `(rpn-func
 \+)' to `(push! (\+ (pop!) (pop!)))'.

 ,----
 | (define-syntax rpn-func
 |   (syntax-rules ()
 |     ((rpn-func x)
 |      (push! (x (pop!) (pop!))))))
 `----

 Sweet! But i think it over complicates things a little bit, and also
 how would we deal with functions that only pop the stack once? or if a
 function has a diffeent name in scheme than what we want its RPN
 equivalent?

 So for now I will only use the macro in the main loop to replace the
 /rpn-*/ functions in the /cond/ that pop two stack elements and also
 have the same identifer in scheme and our RPN calculator.

 We might reconjigger things around if we can find a better way.

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


factorial function
==================

 A simple factorial implementation.

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

 And thats it for a simple commandline RPN calculator.