From ...
From: Erik Naggum
Subject: Re: resonable use of internal functions
Date: 1999/11/18
MessageID: <3151901604345632@naggum.no>#1/1
XDejaAN: 550041724
References: <38318307.B1B8D1B1@inka.de> <38325B95.60768BBB@inka.de>
mailcopiesto: never
XComplaintsTo: newsmaster@eunet.no
XTrace: oslonntp.eunet.no 942912818 16158 193.71.66.49 (18 Nov 1999 08:13:38 GMT)
Organization: Naggum Software; +47 8800 8879 or +1 510 435 8604; fax: +47 2210 9077; http://www.naggum.no
NNTPPostingDate: 18 Nov 1999 08:13:38 GMT
Newsgroups: comp.lang.lisp
[ I have reindented the quoted code according to more standard conventions. ]
* Friedrich Dominicus
 So I came up with this:

 (defun nextval (addto nomfactor denomfactor alternating)
 (+ addto (* alternating
 (/ nomfactor
 denomfactor))))

 of course one can argue about addto. should it be in that function or
 not. I put it here. Now sine looks like

 (defun nextsineval (val x n)
 (let ((alternating (expt 1 n))
 (nomfactor (expt x (+ (* 2 n) 1)))
 (denomfactor (fact (+ (* 2 n) 1))))
 (nextval val nomfactor denomfactor alternating)))

 the thing is as easy for cos now
 (defun nextcosineval (val x n)
 (let ((alternating (expt 1 n))
 (nomfactor (expt x (* 2 n)))
 (denomfactor (fact (* 2 n))))
 (nextval val nomfactor denomfactor alternating)))

 and so on. So it may be that nextval should be a global function and
 that I just internalise nexesineval in sine or the like.
in this particular case, very little is gained by a global function, and
some performance opportunity may easily be lost, so for such a simple
function, I would recommend an FLET binding around the two functions that
use it. incidentally, your compiler may not do common subexpression
elimination on (+ (* 2 n) 1), and in the absence of declarations they
might be quite expensive.
 And I think as simple as nextval is, it's nevertheless a useful
 abstraction worth capturing in a own function.
that doesn't necessarily imply _global_ function. it would also make
sense to write this with a MACROLET (instead of FLET) to capture the
abstraction without the function call overhead and need to redeclare
everything. you could condense your code quite a bit with a macro:
(macrolet ((definenextvalfunction (name cfse)
"Define a helper nextval function, NAME, with common factor
subexpression CFSE. NAME takes arguments VAL, X, N, which may be used by
CFSE. given C = the value of CFSE, NAME returns
n x^c
val + (1) 
c!"
`(defun ,name (val x n)
(declare (fixnum n)) ;ASSUMPTION!
(let* ((cfse ,expression)
(increment (/ (expt x cse) (fact cse))))
(if (evenp n)
(+ val increment)
( val increment))))))
(definenextvalfunction nextsineval (+ (* 2 n) 1))
(definenextvalfunction nextcosineval (* 2 n)))
the use of simpler subexpressions, no extra function calls and avoiding a
call to EXPT of 1 should result in significantly tighter code, even
without declarations. this may not be your concern, of course, but I
also consider the documentation of the above to be far superior to your
use of several temporary variables. that this captures the mathematical
abstraction in one place, rather than a trivial abstraction with the
mathematical abstraction in two different places, would at least to make
make it much more readable to me. the simple reason is that I want to
avoid looking at the internals of a function once it has been written and
debugged. for that reason, I might also use FLETs instead of global
functions since these functions are used only inside your SIN and COS.
there's no point in externalizing what should not be externally used.
if the above flagged assumption is wrong, replace FIXNUM with INTEGER.
(also note that when the scope of a macro is carefully constrained, you
don't need as much "cover" as when it is used globally. the above macro
would be a bad macro if it were made globally available.)
#:Erik

Attention Microsoft Shoppers! MS Monopoly Money 6.0 are now worthless.