To define a new computational command which takes and/or leaves arguments
on the stack, a special form of interactive
clause is used.
(interactive num tag)
where num is an integer, and tag is a string. The effect is
to pop num values off the stack, resimplify them by calling
calc-normalize
, and hand them to your function according to the
function's argument list. Your function may include &optional
and
&rest
parameters, so long as calling the function with num
parameters is legal.
Your function must return either a number or a formula in a form
acceptable to Calc, or a list of such numbers or formulas. These value(s)
are pushed onto the stack when the function completes. They are also
recorded in the Calc Trail buffer on a line beginning with tag,
a string of (normally) four characters or less. If you omit tag
or use nil
as a tag, the result is not recorded in the trail.
As an example, the definition
(defmath myfact (n) "Compute the factorial of the integer at the top of the stack." (interactive 1 "fact") (if (> n 0) (* n (myfact (1- n))) (and (= n 0) 1)))
is a version of the factorial function shown previously which can be used as a command as well as an algebraic function. It expands to
(defun calc-myfact () "Compute the factorial of the integer at the top of the stack." (interactive) (calc-slow-wrapper (calc-enter-result 1 "fact" (cons 'calcFunc-myfact (calc-top-list-n 1))))) (defun calcFunc-myfact (n) "Compute the factorial of the integer at the top of the stack." (if (math-posp n) (math-mul n (calcFunc-myfact (math-add n -1))) (and (math-zerop n) 1)))
The calc-slow-wrapper
function is a version of calc-wrapper
that automatically puts up a `Working...' message before the
computation begins. (This message can be turned off by the user
with an m w (calc-working
) command.)
The calc-top-list-n
function returns a list of the specified number
of values from the top of the stack. It resimplifies each value by
calling calc-normalize
. If its argument is zero it returns an
empty list. It does not actually remove these values from the stack.
The calc-enter-result
function takes an integer num and string
tag as described above, plus a third argument which is either a
Calculator data object or a list of such objects. These objects are
resimplified and pushed onto the stack after popping the specified number
of values from the stack. If tag is non-nil
, the values
being pushed are also recorded in the trail.
Note that if calcFunc-myfact
returns nil
this represents
"leave the function in symbolic form." To return an actual empty list,
in the sense that calc-enter-result
will push zero elements back
onto the stack, you should return the special value `'(nil)', a list
containing the single symbol nil
.
The interactive
declaration can actually contain a limited
Emacs-style code string as well which comes just before num and
tag. Currently the only Emacs code supported is `"p"', as in
(defmath foo (a b &optional c) (interactive "p" 2 "foo") body)
In this example, the command calc-foo
will evaluate the expression
`foo(a,b)' if executed with no argument, or `foo(a,b,n)' if
executed with a numeric prefix argument of n.
The other code string allowed is `"m"' (unrelated to the usual `"m"'
code as used with defun
). It uses the numeric prefix argument as the
number of objects to remove from the stack and pass to the function.
In this case, the integer num serves as a default number of
arguments to be used when no prefix is supplied.