Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast way to type check Symbol in a function with held arguments

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}
like image 319
Mr.Wizard Avatar asked May 01 '11 11:05

Mr.Wizard


1 Answers

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;
like image 90
WReach Avatar answered Nov 09 '22 04:11

WReach