One can test if an argument is a Symbol without a explicit value using:
func[s_Symbol] = ...
If the function has a Hold attribute however, that pattern will match all Symbols, not only those without an explicit value. I could use:
func[s_] /; Head[s] === Symbol = ...
but this comes with a greater performance penalty than I would like. Adding a rule for _Symbol
has a fairly small impact on performance, and HoldFirst
does not appear to have any performance penalty, however Head[s] === Symbol
has a significant overhead on a simple function. Tests with ValueQ
and MatchQ[s, _Symbol]
are even slower.
To clarify, I want to have two different definitions for func
, with one for unassigned Symbols, and one for other arguments.
Is there a faster way?
Timings:
f[x_] = 0;
f /@ Range@1*^6; // Timing
f[s_Symbol] = 1;
f /@ Range@1*^6; // Timing
{0.391, Null}
{0.531, Null}
Remove[f]
SetAttributes[f, HoldFirst]
f[x_] = 0;
f /@ Range@1*^6; // Timing
f[s_] /; Head[s] === Symbol = 1;
f /@ Range@1*^6; // Timing
{0.39, Null}
{1.157, Null}
You can get performance comparable to the fastest exhibited running times by delegating held symbol arguments to a non-held helper function g
:
Remove[f, g]
SetAttributes[f, HoldFirst]
f[_] = 0;
f[s_Symbol] := g[s]
g[_Symbol] = 1;
g[_] = 0;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With