More primitives
User defined functions (attempt 1)
. user-func-from-list
User defined functions (Attempt 2)
Today I am going to add the ability to create user defined functions to
the RPN calculator, and add some more primitives like triginometry
functions and things like truncate, floor etc.
More primitives
===============
We need some more primitives I think to round out the basic
functionality of the calculator, so I will add the functions /sin/,
/cos/, /tan/, /truncate/, /floor/ and /ceiling/.
But first I want to re-write /rpn-func/, so that it has another
argument, the number of arguments the function that is passed to it
takes, so that we can use it for functions like /fact/ that take one
variable.
I would love to be able to write a better version of this function, it
currently only works with functions that take one argument or two, but
I would lave to write a general version that can run a function of
arbitrary arguments. It would probably have to be a macro that
expanded to a function that just had a bunch of nested /let-values/
and ran the func at the end with required funcs.
When expanded it would look something like this, if the function took
two arguments.
,----
| ;; Not working code
| (lambda (stack)
| (let-values (((var1 stack) (pop stack)))
| (let-values (((var2 stack) (pop stack)))
| (push (func var1 var2) stack)))) ;; func being the function
| ;; passed to the macoro
`----
But alas, maybe something to work on later. Or if anyone has any ideas
that would be sick too.
User defined functions (attempt 1)
==================================
How we are going to approach user defined functions is I think, pretty
sweet.
If we enter a list at our command line, the /read/ functions passes
the whole thing along in one go, so we can have a predicate on our
main loop that checks if the input is a list, and then pass that list
to the function that will add it to the dictionary.
We will use a macro to construct a series of embedded /let/ forms that
execute each function in turn, or push the number onto the stack, so
we can have constants in user defined functions.
Unfortunately we have to change our design sligtly by passing the
dictionary to every RPN function call, beacause new user functions
need to refer to the primitives, which can only happen if when
executing the dictionary is available. So now every function in the
dictionary takes two arguments, the stack and the dictionary. Which
isn't great, and I could avoid that by having two dictionaries, the
primitives and the user. But I would prefer to have only one
dictionary, so I have to do the ugly thing.
Now this macro will take the list, minus the head, because that will
be the identifier for the function. And return our function. The macro
will have to to expand from this:
Now the reason that this is attempt is a failure is I was trying to
use a macro at runtime instead of expansion/compile time. So this
isn't going to work unfortunately, but a good learning experience I
think.
User defined functions (Attempt 2)
==================================
So this time around we are going to keep /new-func/ as it is, but
/user-func-from-list/ will be a function that returns a function. And
that function will be the same as the ones in our dictionary, taking
the stack, but we will have to modify all of our dictionary functions
to also take the dictionary, so that our user functions can refer to
all the previously defined functions.
The function will loop over the list and execute each function in
turn, and when the list runs out of functions, return the stack.
And thats it! You can define new functions on the command line, but I
should probably clean up things and maybe make it so you can save
those user defined functions...