myfunc[f_,x_]:= <some definitions>
f should be a pure function like (#^2&) or Function[{x},x^2] or a named
function either self defined, like
f[x_]:=x^2 or g[x_]=x^2
or built-in like Sin, Log, ...
How can I test if f is any of these, to be able to yield a message on
wrong input?
I found that the pure-functions have Head Function, but all the others
have Head Symbol, so asking for the head is not sufficient.
--
_________________________________________________________________
Peter Breitfeld, Bad Saulgau, Germany -- http://www.pBreitfeld.de
> Suppose I have a function eg
>
> myfunc[f_,x_]:= <some definitions>
>
> f should be a pure function like (#^2&) or Function[{x},x^2] or a named
> function either self defined, like
>
> f[x_]:=x^2 or g[x_]=x^2
>
> or built-in like Sin, Log, ...
>
> How can I test if f is any of these, to be able to yield a message on
> wrong input?
>
> I found that the pure-functions have Head Function, but all the others
> have Head Symbol, so asking for the head is not sufficient.
it might not be possible to really check that what you get is o.k. for
what you do, but you could at least check whether a DownValue that
matches one argument is defined. The correct number of arguments could
be checked like this:
MemberQ[
Cases[
DownValues[f],
Verbatim[RuleDelayed][_[args_], _] :> Length[Unevaluated[args]]
],
1]
The above will only work for user defined functions, the internal
functions (most, but I think not all are in the Context "System`")
usually have empty DownValues, although they behave as they would have
DownValues defined. For these you could try to analyze the
SyntaxInformation, e.g. like this:
Length[DeleteCases[
"ArgumentsPattern" /. SyntaxInformation[Log], _Optional]] == 1
but there might be internal functions that are missing
SyntaxInformation, so this might not be 100% robust.
Depending on what you do there might be better approaches to catch
invalid input. E.g. it is often possible to just try what you want and
Catch error messages so the function aborts when the argument you assume
to be a function doesn't behave well.
hth,
albert
I don't believe that it is possible to do this in a reliable way, so
my suggestion is that you don't test this at all. Trying to test it
might cause more harm than good.
A "function" defined like f[x_] := x^2 will have DownValues (check
DownValues[f]). But now consider something like g[n_][x_] := x^n. I,
as a user, would expect that I can pass e.g. g[2] to your function,
but g[2] is neither a Function, nor a Symbol ... furthermore, g
doesn't even have DownValues (only SubValues). Built-in functions
don't even have DownValues (or even worse: will only have them after
they have been used for the first time in a session).
Also, the fact that a symbol has DownValues is no guarantee that it
behaves like a "proper" function..
Szabolcs
P.S. If myfunc[] takes functions in the mathematical sense (rather
than in a programming sense), sometimes it is advantageous to use a
syntax similar to myfunc[1+x^2+x^3, x] rather than myfunc[ 1+#^2+#^3
& ]. However, whether this is an advantage or disadvantage depends on
what myfunc[] actually is/does.
I think that the easiest way is to check whether the object will
evaluate to anything (normally in these situations you'll know what
type of arguments you want your function to act on). This can be done
using ValueQ.
Simon
Good day,
This way to do it should be ok for almost all non-pathological cases :
In[1]:= myfunc::nfun="argument `1` should be a function.";
In[2]:= myfunc[(f_?NumericQ|f_List|f:(True|False)),x_]:=
(Message[myfunc::nfun,f]; HoldForm@myfunc[f,x]);
myfunc[f_Symbol /; DownValues[f]=={} && Attributes[f]=={},x_]:=
(Message[myfunc::nfun,f]; HoldForm@myfunc[f,x]);
myfunc[f_,x_]=f[x];
A few tests :
In[5]:= f1=#^2&;
In[6]:= f2[x_]=x^2;
In[7]:= f3=Function[{x},x^2];
In[8]:= myfunc[f1,x]
Out[8]= x^2
In[9]:= myfunc[f2,x]
Out[9]= x^2
In[10]:= myfunc[f3,x]
Out[10]= x^2
In[11]:= myfunc[ff,x]
myfunc::nfun: argument ff should be a function.
Out[11]= myfunc[ff,x]
In[12]:= myfunc[1,x]
myfunc::nfun: argument 1 should be a function.
Out[12]= myfunc[1,x]
In[13]:= myfunc[{1,2},x]
myfunc::nfun: argument {1,2} should be a function.
Out[13]= myfunc[{1,2},x]
In[14]:= myfunc[True,x]
myfunc::nfun: argument True should be a function.
Out[14]= myfunc[True,x]
In[15]:= myfunc[Sin,x]
Out[15]= Sin[x]
--
V.Astanoff
In general, I add my voice to what Szabolcs said - he
formulated the difficulties associated with such a check very nicely.
IMO, trying to implement full typing in an untyped language is generally
not a rewarding activity.
What I do sometimes for my own functions is to add a check of the
form
fn[x:(_Symbol|_Function)],
which is not a complete test (so does not guarantee the correctness
of execution with a passed argument, especially for Symbol), and also,
as Szabolcs pointed out, excludes the SubValues case. But this is often good
enough to catch most errors. If you start using constructs for which
this will not be good enough, you will for sure be able to find acceptable
for you ways to work around this problem.
Regards,
Leonid
NoFunc::nofun = "Parameter `1` muss eine Funktion sein.";
NoFunc[f_] :=
If[Not[(Head[f] === Function) || (Head[f] === Symbol &&
((DownValues[f] =!= {}) || (Attributes[f] =!= {})))],
Message[kF::nofun, f]; Abort[]]
ClearAll[FunctionQ];
FunctionQ[f_] :=
(Head[f] === Function) ||
(AtomQ[f] && Head[f] === Symbol && !NumericQ[f] && (
DownValues[f] =!= {} || Attributes[f] =!= {}
))
Then you can use the above function as an argument check like below:
ClearAll[myfunc];
myfunc::nfun = "argument `1` should be a function.";
myfunc[f_?FunctionQ, x_] = f[x];
myfunc[__] := Message[myfunc::nfun, f];
and the examples provided in the discussion work.
An borderline case might be:
myfunc[C, x]
C[x]
because C is a standard name for constants and has a particular
definition.
Note that the check for NumericQ is necessary to avoid slipping in
constants like I or E.
ADL
ClearAll[FunctionQ];
FunctionQ[f_] := (functionQtest2[f] || functionQtest3[f]) &&
functionQtest1[f];
ClearAll[functionQtest1,functionQtest2,functionQtest3];
functionQtest1[f_Symbol] := (Length[StringPosition[ToString
[f::usage,OutputForm],"["]]>0);
functionQtest1[___] := True;
functionQtest2[f_] := (Head[f]===Function);
functionQtest3[f_] := (AtomQ[f] && (Head[f]===Symbol) && (!NumericQ
[f]) && (
(DownValues[f]=!={})||(Attributes[f]=!={})
));
The functionQtest1 test comes from a little heuristics about usage
messages.
Then, the following comes out:
In:= FunctionQ[Red]
Out= False
In:= FunctionQ[\[ScriptCapitalA]]
Out= False
In:= FunctionQ[Log]
Out= True
In:= FunctionQ[Algebraics]
Out= False
In:= FunctionQ[Log[Sin[#]] &]
Out= True
In:= systemFunctions = Select[ToExpression /@ Names["System`*"],
FunctionQ];
In:= systemFunctions // Length
Out= 1661
ADL
On Jul 15, 1:09 pm, Peter Breitfeld <ph...@t-online.de> wrote:
At the moment, after heavy trying, I use to test if f is not to be
considered a function:
KeineFunktion::nofun="Parameter `1` sollte eine Funktion sein.";
KeineFunktion[f_]:=
If[Not[
(Head[f]===Function) ||
(Head[f] === Symbol &&
((DownValues[f] =!= {}) ||
(Intersection[Attributes[f],{NumericFunction}] =!= {}))) ],
Message[KeineFunktion::nofun, f]; True, False];
This passes nearly all usual cases, except "Set", which will be
considered a function, whereas e.g. SetDelayed, Rule or constants where
not. This is, because Set has DownValues.
One -- in my opinion not very complicated case -- is with functions
which are defined by SubValues. So
u[x_][y_]:=x^2+y
KeineFunktion[u[x]] --> True
KeineFunktion[u] --> True
but
KeineFunktion[u[x][#]&] --> False (not astonishing)
The length of "systemFunctions" you calculated is bigger than the length
calculated with my function, because I have them restricted to
NumericFunktion.