Subject: Re: resonable use of internal functions From: Erik Naggum <erik@naggum.no> Date: 1999/11/18 Newsgroups: comp.lang.lisp Message-ID: <3151901604345632@naggum.no> [ I have reindented the quoted code according to more standard conventions. ] * Friedrich Dominicus <Friedrich.Dominicus@inka.de> | So I came up with this: | | (defun next-val (add-to nom-factor denom-factor alternating) | (+ add-to (* alternating | (/ nom-factor | denom-factor)))) | | of course one can argue about add-to. should it be in that function or | not. I put it here. Now sine looks like | | (defun next-sine-val (val x n) | (let ((alternating (expt -1 n)) | (nom-factor (expt x (+ (* 2 n) 1))) | (denom-factor (fact (+ (* 2 n) 1)))) | (next-val val nom-factor denom-factor alternating))) | | the thing is as easy for cos now | (defun next-cosine-val (val x n) | (let ((alternating (expt -1 n)) | (nom-factor (expt x (* 2 n))) | (denom-factor (fact (* 2 n)))) | (next-val val nom-factor denom-factor alternating))) | | and so on. So it may be that next-val should be a global function and | that I just internalise nexe-sine-val 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 next-val 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 re-declare everything. you could condense your code quite a bit with a macro: (macrolet ((define-next-val-function (name cfse) "Define a helper next-val 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)))))) (define-next-val-function next-sine-val (+ (* 2 n) 1)) (define-next-val-function next-cosine-val (* 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.