I have a function-defining function
SetAttributes[DefFn, HoldAll];
DefFn[f_[args___], body_] :=
f[args] := body;
I am trying to modify this function to record the function name and the values of its arguments on a stack for error-reporting purposes. I have a function WithStackFrame
which adds this information to a list, and I am inserting a call to this function into each definition:
DefFn[f_[args___], body_] :=
f[args] := WithStackFrame[f,body];
This allows me to give a stack backtrace when reporting errors. This works. The problem comes when I try to store also the values of the function arguments. A naive
DefFn[f_[args___], body_] :=
f[args] := WithStackFrame[{f,{args}},body];
does not work because args
is actually the sequence of patterns. The closest I have got is
DefFn[f_[args___], body_] :=
Module[{argValueExprs,x},
argValueExprs = {args} /. x_Pattern :> x[[1]];
f[args] := WithStackFrame[{f,argValueExprs},body]];
For the purpose of testing, you can use
WithStackFrame[sf_, expr_] := Print[sf];
However, running this gives
DefFn[f[x_], x^2];
f[3]
(*
{f,{x}}
*)
when I really want {f,{3}}
. For some reason, the x
is not being evaluated in a scope in which the function arguments are visible.
WithStackFrame
needs attributeHoldAll
for the test case to work as stated. $\endgroup$HoldFirst
rather thanHoldAll
, to allow the body to evaluate. $\endgroup$HoldFirst
seems not really necessary, it was my mistake (I had a definition forx
hanging around) that caused it was needed in the first place. Once the function does what it is supposed, the actual arguments will be used so the hold attribute should usually not be necessary at all, so it might be best to ignore my comment... $\endgroup$WithStackFrame
, may be expressions which may evaluate (the function being executed may beHoldAll
itself), so in that caseHoldFirst
forWithStackFrame
would prevent that. $\endgroup$