From: Friedrich Dominicus
Subject: resonable use of internal functions
Date: 
Message-ID: <38318307.B1B8D1B1@inka.de>
On a question in an newsgroup about algorithms on asked for an
algrorithms from sin. I grabbed my old Bronstein and found a definiton
there. I tried to translate that into Common Lisp (I'm aware, that sin
is there ready for use, I just take it as an exercise for me;-)

So I come up with this implementation

(defun sine (x)
  (flet ((next-factor (val n)
		(+ val (* (expt -1 n)  
			  (/ (expt x (+ (* 2 n) 1)) 
			     (fact (+ (* 2 n) 1)))))))
	(labels ((inner-sine (val n)
		  (let ((new-val (next-factor val n)))
		      (if (good-enough (abs val) (abs new-val))
			   (float new-val)
			(inner-sine new-val (1+ n))))))
	  (inner-sine 0 0))))

My question is about the style in which it is written and if the usage
of inner functions seems to be appropriate here.

And I have another questoin about flet and labels. And I wonder if there
is a case where I just can use flet but not labels. Just for the fun of
it (and despite what was writte in the Hyperspec), I changed the labels
before inner-sine to flet and of course then this function can't be
found. But I really don't know when I should use flet and labels. In
recursive functions the answer is clear, I just can use labels but
instead of flet I used labels and that worked quite fine. So some
comments would be very welcome

Regards
Friedrich

From: Robert Monfera
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <38318D2F.F8DDE18C@fisec.com>
Friedrich Dominicus wrote:

> And I wonder if there
> is a case where I just can use flet but not labels. Just for the fun of
> it (and despite what was writte in the Hyperspec), I changed the labels
> before inner-sine to flet and of course then this function can't be
> found. But I really don't know when I should use flet and labels. In
> recursive functions the answer is clear, I just can use labels but
> instead of flet I used labels and that worked quite fine. So some
> comments would be very welcome

Quite often you may achieve the same thing in CL various ways, of
various generalization.  You may consider LABELS a generalization of
FLET, and use it all the time.  It's the same thing with LET vs. LET* or
IF vs. WHEN.  For two reasons, you may want to prefer using the more
specific of the alternatives, because your code will be clearer (looking
at FLET, you know there is no recursion - looking at LABELS, you would
not know, and many people would be quick to assume there _is_
recursion), and the same goes with your compiler (though they may figure
it out anyway). 

Robert
From: Barry Margolin
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <M3gY3.21$Nh.225@burlma1-snr2>
In article <·················@inka.de>,
Friedrich Dominicus  <···················@inka.de> wrote:
>On a question in an newsgroup about algorithms on asked for an
>algrorithms from sin. I grabbed my old Bronstein and found a definiton
>there. I tried to translate that into Common Lisp (I'm aware, that sin
>is there ready for use, I just take it as an exercise for me;-)
>
>So I come up with this implementation
>
>(defun sine (x)
>  (flet ((next-factor (val n)
>		(+ val (* (expt -1 n)  
>			  (/ (expt x (+ (* 2 n) 1)) 
>			     (fact (+ (* 2 n) 1)))))))
>	(labels ((inner-sine (val n)
>		  (let ((new-val (next-factor val n)))
>		      (if (good-enough (abs val) (abs new-val))
>			   (float new-val)
>			(inner-sine new-val (1+ n))))))
>	  (inner-sine 0 0))))
>
>My question is about the style in which it is written and if the usage
>of inner functions seems to be appropriate here.

Yes, it does.  By defining the NEXT-FACTOR function, you simplify the
definition of INNER-SINE; the alternative would be to put that complex
formula in the LET.  It could have been defined as a global function, but
if it's only useful for defining SINE then there's no need to add it to the
external namespace; this lets readers know that this isn't a general
purpose function, but just a name for an internal computation used for this
function.

The same thing goes for INNER-SINE.  It's a helper function that's only
useful for SINE.  Since nothing else can use it, it might as well be
internal.

>And I have another questoin about flet and labels. And I wonder if there
>is a case where I just can use flet but not labels. Just for the fun of
>it (and despite what was writte in the Hyperspec), I changed the labels
>before inner-sine to flet and of course then this function can't be
>found. But I really don't know when I should use flet and labels. In
>recursive functions the answer is clear, I just can use labels but
>instead of flet I used labels and that worked quite fine. So some
>comments would be very welcome

It's mostly a matter of style.  By using FLET for non-recursive functions,
you let other readers of the program know your intentions better.  When I
looked at the above function, I knew to scan INNER-SINE looking for the
recursion, but I could tell that NEXT-FACTOR doesn't have this complication
because it was defined with FLET.  It's like the decision about whether to
use LET or LET* -- in many cases it doesn't make a difference to the
program, but LET* is used to alert readers that there are dependencies
between the variables being bound.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Robert Monfera
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <38334EED.93E97C84@fisec.com>
Rainer Joswig wrote:

> Source code is just m-. away.

Although I am using this, I have difficulties when going back to where I
came from.  Yes, I have a key binding for the previous history element,
but that fails if 
- the source code is in the same file as the one I was in
- there are nested searches, possibly touching one file more than once.

What I would need is something like the go back button in SAP, so that
the source lookup becomes a jump that is quick (cheap) to get out of. 
Maybe it's available, but I haven't found it in LW.  Is there something
similar for the Allegro IDE?  Does it have a clean way of getting back
from arbitrarily nested lookups?

If we already talk about IDE's, I'm wondering why duplicates are
collected in history lists.  When I evaluate the same thing three times,
it will be on the history list three times for no benefit.  It would be
easy to do an EQUAL.

Robert
From: Friedrich Dominicus
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <3833A3B8.65CD77AC@inka.de>
Rainer Joswig wrote:
> 
> In article <·················@inka.de>, ···················@inka.de wrote:
> 
> > Of course one can write it this way but I personally think that your
> > solution does not give hints on what's going on.
> 
> That's what documentation is for.

Of course documentation it one way but self-documenting code is another
one. And I prefer to name a temporary calculation than the calculation
in place. And just in case docs are not available for whatever reason
the code is there.

> >
> > Now, maybe but I trade normaly readability for time and space. I think
> > that may pay off sooner or later.
> 
> -> Time to write code and space on your screen.

I try to keep my functions short and in fact your code is just one line
or so shorter than mine, I think this is quite a prive worth to pay. And
to write some-variabels and a let is IMO not too time-cosuming. 

But I would agree that one should spend some time learning what's there
for getting ones work done.

Regards
Friedrich
From: Erik Naggum
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <3151901604345632@naggum.no>
[ I have reindented the quoted code according to more standard conventions. ]

* 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.
From: Friedrich Dominicus
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <38342D87.A438AF19@inka.de>
Erik Naggum schrieb:

> 
>   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.

That are points I would consider after I get it right and maybe there is
not much gained here. But this function can easily applied to other
chains of rationals. (e.g epxt ...)

> 
> | 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. 

This is or might be true. And maybe it's even not a good decision ot
make it a global function, but it's useful and avoids some some
repetition.


 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))))))

This is a bit beyond my horizont and I do not know enough about Common
Lisp to judge when which construct should be used. But I thought about
something simular but haven't followed that path further. So I take it
as a thing on my list I should learn ;-)


>   (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. 

I agree. It seems to be a nicer solution. 

> 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.

That is a good point.

Regards
Friedrich
From: Fernando Mato Mira
Subject: &aux (was: resonable use of internal functions)
Date: 
Message-ID: <38341029.1E55492E@iname.com>
Robert Monfera wrote:

> What do you think about this version, however, as a way of doing the
> same thing as LET, but saving on typing?  I would guess it compiles the
> exact same way as if it used LET instead.
>
> (defun next-sine-val (val x n &aux (nominator (expt x (+ (* 2 n) 1)))
>                                    (denominator (fact (+ (* 2 n) 1)))
>                                    (alternating (expt -1 n)))
>   (next-val val nominator denominator alternating))

What I _personally_ think is "Yuck". I never liked &aux. I always thought
it was more of a legacy thing, and gives me a bad AutoLisp vibe.
From: Barry Margolin
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <6sKY3.87$Nh.1300@burlma1-snr2>
In article <·······················@194.163.195.67>,
Rainer Joswig <······@lavielle.com> wrote:
>Learn to use the tools to look up the information.
>If you need documentation, write **documentation**.
>Don't waste your time with writing unused code.

Taken to the extreme, this would justify:

;; This function computes factorials
(defun func1 (arg)
  ...)
;; This function writes the printed representation of an object.
;; ARG1 is the object to print, :ARG2 is the stream to print it on,
;; :ARG3 is the radix to use for integers, ...
(defun func2 (arg1 &key (arg2 *standard-output*) (arg3 *print-radix) ...)
  ...)

Why do we need mnemonic function names as long as we have good
documentation?

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Barry Margolin
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <VmKY3.86$Nh.1300@burlma1-snr2>
In article <·······················@194.163.195.67>,
Rainer Joswig <······@lavielle.com> wrote:
>Learn to use the tools to look up the information.
>If you need documentation, write **documentation**.
>Don't waste your time with writing unused code.

Self-documenting code is better than manually documented code.  Manual
documentation can more easily become inconsistent with the code.  Self
documentation shows up in the debugger, pretty-printing code, etc.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Robert Monfera
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <38343B3D.CBC46BD5@fisec.com>
Barry Margolin wrote:
> 
> In article <·······················@194.163.195.67>,
> Rainer Joswig <······@lavielle.com> wrote:
> >Learn to use the tools to look up the information.
> >If you need documentation, write **documentation**.
> >Don't waste your time with writing unused code.
> 
> Self-documenting code is better than manually documented code.  Manual
> documentation can more easily become inconsistent with the code.  Self
> documentation shows up in the debugger, pretty-printing code, etc.

What are the pros and conses (sic) of &aux, as an alternative to let in
some cases?  I like &aux, but I have a vague recollection that it may be
retrograde to use it (I can not think of the reason).

Robert
From: Erik Naggum
Subject: Re: resonable use of internal functions
Date: 
Message-ID: <3151940280815662@naggum.no>
* Robert Monfera <·······@fisec.com>
| What are the pros and conses (sic) of &aux, as an alternative to let in
| some cases?

  this may sound silly, but if you can avoid a few LET bindings among many,
  it's going to impact your maximum indentation favorably.  such concerns
  should not be dismissed _too_ lightly, although it might be a good
  argument in its favor.

  in some cases, however, &AUX is useful to avoid a LET binding or a SETQ
  that does nothing but resolve a designator or some other relevant work on
  an argument.  it's a difficult to spell out any rules for when this is
  good style, though.

| I like &aux, but I have a vague recollection that it may be retrograde to
| use it (I can not think of the reason).

  I like having &AUX in the language.  it tells me somebody thought about
  something important and came up with a solution.  I'm not sure _exactly_
  what they thought about all that time, but it's evidence of intelligence
  at work.  in fact, the whole lambda list concept in Common Lisp gives me
  that feeling, with all its variations and intriguing details.

#:Erik
-- 
  Attention Microsoft Shoppers!  MS Monopoly Money 6.0 are now worthless.
From: Kaelin Colclasure
Subject: Wither &aux (was Re: resonable use of internal functions)
Date: 
Message-ID: <g%YY3.32$g6.8457@newsin1.ispchannel.com>
Erik Naggum <····@naggum.no> wrote in message
·····················@naggum.no...
> * Robert Monfera <·······@fisec.com>

[...]
> | I like &aux, but I have a vague recollection that it may be retrograde
to
> | use it (I can not think of the reason).
>
>   I like having &AUX in the language.  it tells me somebody thought about
>   something important and came up with a solution.  I'm not sure _exactly_
>   what they thought about all that time, but it's evidence of intelligence
>   at work.  in fact, the whole lambda list concept in Common Lisp gives me
>   that feeling, with all its variations and intriguing details.

One place where &aux is often much more convenient than let is in macro
expansions and other "generated" code. Where you accomodate a lambda-list,
you also automatically accomodate lexical locals as well with no additional
coding or syntax.

I too privately considered that &aux was probably some hold-over from an
elder dialect -- until I hit upon this usage, and suddenly it made perfect
sense to me why it should be retained. :-)

-- Kaelin