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