How to programmatically modify a function definition
This is my first time wading into metaprogramming in Mathematica, so take this with a pinch of salt. I can get the DownValues
of myfunction
and strip out the cases of Print
commands, then build a new function newfunction
by setting DownValues
like so:
(* any old function will do *)
myfunction[x_, y_] := Module[{p = 0},
p = x^2 + y^2;
Print["test1: " <> ToString@p];
If[p < 1, p = p^2 + 1, p = y - x];
Print["test2: " <> ToString@p];
Do[
Print["blah" <> ToString@i];
, {i, 3}];
Return[p]
]
DownValues[newfunction] = ReleaseHold[
DeleteCases[
DownValues[myfunction][[1]],
fn_[___] /; fn === Print, Infinity,
Heads -> True
] /. myfunction -> newfunction
];
myfunction[6, 3]
(*
> test1: 45
> test2: -3
> blah1
> blah2
> blah3
returns -3
*)
newfunction[6,3]
(* returns -3 *)
You might want to look into ways to suppress Print
though, because the above technique looks pretty dangerous and will probably go wrong in unexpected ways.
Suppress Print[ ]s?
To operate on notebooks
Let nb
be the notebook you want to alter obtained with NotebookGet[]
. For instance, it could be nb = NotebookGet[EvaluationNotebook[]]
. Instead of EvaluationNotebook[]
, you could have something like First@Select[Notebooks[], Information[#, "FileName"] === "MyProg" &]
.
nb /. HoldPattern@RowBox[{
x___, Optional[";", ";"],
RowBox[{"Print", "[", ___, "]"}],
Optional[";", ";"], y___}] :>
RowBox[{x, y}] // NotebookPut
Note: This will not extensively tested. Like the method below, it may result in errors in the code. It should work well if each Print[]
statement occurs in a CompoundExpression
.
To operate on definitions in the kernel
The function cleanup[sym, pat]
will delete all expressions matching pat
from the definitions of a symbol sym
. Use _Print
to delete Print
statements.
cleanup[sym_Symbol, pat_] :=
Language`ExtendedFullDefinition[sym] =
DeleteCases[Language`ExtendedFullDefinition[sym], pat, Infinity]
Deleting Print[..]
as an argument to something other than CompoundExpression
may result in errors on execution. For example:
DeleteCases[Hold[Module[{}, Print["Hi there!"]]], _Print,
Infinity] // ReleaseHold
Module::argmu: Module called with 1 argument; 2 or more arguments are expected.
(* Module[{}] *)
Adding a semicolon, Module[{}, Print["Hi there!"];]
, prevents the error.
Example
Example function to clean up, showing a variety of values (DownValues
, SubValues
and UpValues
):
ClearAll[addto];
call : addto[x_, y_] := (Print["main routine called: ",
HoldForm[call]]; x + y);
call : addto[x_][y_] := (Print["operator form called: ",
HoldForm[call]]; addto[x, y]);
addto /: call :
addto[x_] + y_ := (Print["upvalue form called: ", HoldForm[call]];
addto[x, y]);
Test:
addto[3][4]
operator form called: addto[3][4]
main routine called: addto[3,4]
(* 7 *)
addto[3] + 5
upvalue form called: 5+addto[3]
main routine called: addto[3,5]
(* 8 *)
cleanup[addto, _Print]
(* Language`DefinitionList[HoldForm[addto] -> {OwnValues -> {}, SubValues -> {HoldPattern[call : addto[x_][y_]] :> CompoundExpression[addto[x, y]]}, UpValues -> {HoldPattern[call : addto[x_] + y_] :> CompoundExpression[addto[x, y]]}, DownValues -> {HoldPattern[call : addto[x_, y_]] :> CompoundExpression[x + y]}, NValues -> {}, FormatValues -> {}, DefaultValues -> {}, Messages -> {}, Attributes -> {}}] *)
Test again:
addto[3][4]
(* 7 *)
addto[3] + 5
(* 8 *)
That's not a real answer... But I failed to format it as a comment. Again.
You're opening a deep can of worms now, called "metaprogramming".
Please search for "metaprogramming" and discover excellent posts by Leonid Shifrin and others.
In your particular case:
increment = Function[{x}, Print[x]; x + 1]
You can try something like this:
increment //. {
HoldPattern @ CompoundExpression[a___, _Print, b___] :>
CompoundExpression[a, b]}
The original increment has a tree representation:
The result will look like:
Generally speaking you can use rewrite rules to manipulate the structure of the expression (most of the times you will have to inactivate the expression with 'Hold' and friends)