MathGroup Archive 1995

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Programming

  • To: mathgroup at smc.vnet.net
  • Subject: [mg2834] Re: [mg2819] Programming
  • From: villegas (Robert Villegas)
  • Date: Sat, 23 Dec 1995 03:18:55 -0500
  • Organization: Wolfram Research, Inc.

In article <4bandr$cqu at dragonfly.wri.com> Preston Nichols  
<nichols at godel.math.cmu.edu> writes:


> If you want your extension of BuiltIn to be more invisible,
> 
> Unprotect[BuiltIn];
> BuiltIn[args___] :=
> 	If[ Head[ resultOfBuiltIn=BuiltIn[args] ] =!= BuiltIn,
> 		resultOfBuiltIn,
> 		MyOperation[args] ]
> Protect[BuiltIn];
> 
> Modifying built-in commands is generally rather risky, but I think  
> something like this should be pretty safe.


This simple overlay for BuiltIn will not work because it traps
absolutely every call to BuiltIn, even the one inside your own
code where you want to evaluate BuiltIn normally using the kernel's
built-in definitions

   Head[ resultOfBuiltIn=BuiltIn[args] ] =!= BuiltIn

So your code calls itself, which calls itself, _ad infinitum_.
Example:


In[1]:= Unprotect[Integrate];

In[2]:= Integrate[args___] :=
        If[ Head[ resultOfIntegrate=Integrate[args] ] =!= Integrate,
                resultOfIntegrate,
                MyOperation[args] ]
                        
In[3]:= Protect[Integrate];

In[4]:= Integrate[x^3, x]

$RecursionLimit::reclim: Recursion depth of 256 exceeded.

Out[4]= resultOfIntegrate

In[5]:= Integrate[f[x], x]

$RecursionLimit::reclim: Recursion depth of 256 exceeded.

Out[5]= resultOfIntegrate


That's why you need something to prevent your own rule from firing
inside your code.


The method I chose uses a flag that is reset as soon as
your overlay of BuiltIn is called.  It remains set for the duration
of your program, and effectively announces "My overlay has already
been called and is currently in progress, so don't call it again."
Once your overlaid program is finished and has decided what result
to return (the built-in one or MyOperation), the flag reverts to
its usual value.  The next time the user uses BuiltIn, your program
will be called again.


There are other ways to do it, but this way is one of the simpler ones.


As Todd Gayley pointed out to me a while back, though, this method
fails to invoke your overlay if there are nested uses of the function
in the original input.  For instance, the tecnique I gave in response
to Jack Goldberg will not trap all three calls to f in this
expression:

   f[ f[1, 2], f[3, 4] ]

It will trap the outermost call, then evaluate the whole thing using
normal rules for f, never again calling your overlay.  I just thought
of a possible solution to that weakness, and the new method isn't far
from the original in structure:


   Possible General Technique even for Nested Calls
=======================================================

Unprotect[SomeFunction]

$SomeFunctionStatus = 0

SomeFunction[args___] :=
 MyExtraCode[ SomeFunction[args] ] /; EvenQ[$SomeFunctionStatus++]

=======================================================



As an example, let's have Module report every call to itself by printing
to the screen.


In[1]:= Unprotect[Module]

Out[1]= {Module}

In[2]:= $ModuleStatus = 0

Out[2]= 0

In[3]:= Module[args___] :=
     EvenQ[$ModuleStatus++]


(* A couple tests: *)

In[4]:= Module[{x, y}, x^2 - y^2]
                2    2
Module[{x, y}, x  - y ] was called

           2      2
Out[4]= x$2  - y$2

In[5]:= Module[{x, y}, {Module[{u}, u], Module[{v}, v]} ]
Module[{x, y}, {Module[{u}, u], Module[{v}, v]}] was called
Module[{u}, u] was called
Module[{v}, v] was called

Out[5]= {u$4, v$5}


The basis for this trick is that we want to trap every call to a
function, such as Module or Integrate, and do something, then call
that function normally using the built-in rules that would have
been used if we hadn't attached any baggage to the function.  So
calls to the function occur in pairs:  first, our overlay program;
second, the "real" call.  The theory is that every other call to
the function will be a "real" one, so we call our overlay if the
counter is even, but otherwise let the function fall through to
its normal rules.


I haven't tested this since I just thought of it, so I don't know
how well it works.  The theory sounds right, so maybe it will endure
some more exercise.  Let me know how you break it...



Robby Villegas


  • Prev by Date: Re: Programming
  • Next by Date: Help, Monte Carlo Simulations
  • Previous by thread: Re: Programming
  • Next by thread: Re: Programming