First, let us consider some sample benchmarks:
In[100]:= f[x_]:=x^2;
In[102]:= Do[#^2&[i],{i,300000}]//Timing
Out[102]= {0.406,Null}
In[103]:= Do[f[i],{i,300000}]//Timing
Out[103]= {0.484,Null}
In[104]:= Do[Function[x,x^2][i],{i,300000}]//Timing
Out[104]= {0.578,Null}
Pure functions are often (much) faster for 2 reasons. First, anonymous pure functions (those defined with the slots - #
and &
) do not need to resolve name conflicts for variable names. Therefore, they are somewhat faster than pattern-defined ones, where some name conflict resolution takes place. But you see that pure functions with named variables are actually slower, not faster, than pattern-defined ones. I can speculate that this is because they also have to resolve possible conflicts inside their body, while rule-based ones ignore such conflicts. In nay case, speed differences are of the order of 10-20 %.
Another, and much more dramatic, difference is when they are used in functions such as Map, Scan, Table, etc, because the latter auto-compile on large numerical (packed) lists. But while pure functions can often be compiled, pattern-defined ones fundamentally can not, so this speed gain is inaccessible to them. For example:
In[117]:= ff[x_] := Sqrt[x];
In[116]:= Map[Sqrt[#] &, N@Range[100000]]; // Timing
Out[116]= {0.015, Null}
In[114]:= Map[ff, N@Range[100000]]; // Timing
Out[114]= {0.094, Null}