______________________
RPN CALCULATOR AGAIN
lro
______________________
<20190104 Fri>
Table of Contents
_________________
New data structure for functions
alist
.. insertion
.. update
calling a function in the loop
Main loop
Conslusion
throught it. I might also add a FORTH style syntax for defining your own
functions.
New data structure for functions
================================
I was thinking that we we need a new data structre for our functions,
an alist where the car is the symbol we want to use as an identifier
and the cdr being the function itself, taking one argument, the stack,
and returning the stack. This will be our "dictionary". But as an
exercise we will also include a very simple alist implementation.
alist
=====
We need some fundamental operations for an alist, retrieve value,
insertion, deletion, update. Luckily R7RS provides some functions for
us, like /assq/ which retrieve a value from an alist, and if it
doesn't exist, return `false'.
nsertion
~~~~~~~~~
To insert into an alist we must search the alist and make sure that
that key doesn't alredy exist, and if it doesn't then append it to our
list with our chosen values.
,
 (define (insertintoalist key val alist)
 (let ((mem? (assq key alist)))
 (if mem?
 (updatealist key val alist)
 (append alist (list (cons key val))))))
`
update
~~~~~~
To update an alist, we have to find the key, and change its associated
value, and return the modified dictionary. We will also assume that
/key/ exists in the alist.
We need to find the index into the list whee our key is, so we
traverse our alist until we find it, then we can use that index in
/listset!/ which isn't functional but the easiest way of doing it.
,
 (define (indexinalist key alist)
 (let loop ((list (listcopy alist))
 (index 0))
 (if (= (length list) 0)
 #f
 (let ((listheadkey (car (car list))))
 (if (eq? listheadkey key)
 index
 (loop (cdr list) (+ index 1)))))))

 (define (updatealist key newval alist)
 (let ((index (indexinalist key alist)))
 (listset! alist index (list (cons key newval)))
 alist))
`
calling a function in the loop
==============================
Now how is calling a function from our main loop going to work? Well
first we need too check if the symbol is in the dictionary, if it
isn't then we need to return an error. If it is then we need to use
/assq/ o get the function and run it pasing it the stack. We will need
a helper function, /runfunc/ that takes the symbol, dictionary and
the stack.
,
 (define (runfunc sym dict stack)
 (let ((func (assq sym dict)))
 (if func
 ((cdr func) stack)
 (begin
 (display "ERROR: symbol not in dictionary: ")
 (display sym)
 (newline)
 stack))))
`
==================
This will be the initial dictionary that is passed to the main loop,
it wil hold all of our "primitives" that we can add to later.
,
 (define initdict
 (list (cons '$ (lambda (stack)
 (letvalues (((var stack) (pop stack)))
 (display var)
 (newline)
 stack)))
 (cons '+ (lambda (stack) (rpnfunc + stack)))
 (cons ' (lambda (stack) (rpnfunc  stack)))
 (cons '* (lambda (stack) (rpnfunc * stack)))
 (cons '/ (lambda (stack) (rpnfunc / stack)))
 (cons '% (lambda (stack) (rpnfunc modulo stack)))
 (cons '! (lambda (stack)
 (letvalues (((var stack) (pop stack)))
 (push (fact var) stack))))
 (cons '/ (lambda (stack) (rpnfunc / stack)))
 (cons 'dup (lambda (stack) (dup stack)))))
`
Main loop
=========
The main loop now only checks for symbols and passes any to our
/runfunc/ function. And we have added our dictionary to the loop, so
that we can modify it in our REPL when we add that functionality.
,
 (let loop ((input (read))
 (stack '())
 (dict initdict))
 (cond
 ((number? input) (loop (read) (push input stack) dict))
 ((symbol? input) (loop (read) (runfunc input dict stack) dict))
 (else (begin
 (display "ERROR not valid input: ")
 (display input)
 (newline)
 (loop (read) stack dict)))))
`
Conslusion
==========
So next time we will add the ability to add our own user defined
functions. In the mean time feel free to email me some feedback at
lro@sdf.org, or even try adding some functions to the initial
dictionary yourself, like some trigonometry functions or vector math
like dot or cross product.