Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Determine if a parameter is a function

48 views
Skip to first unread message

Peter Breitfeld

unread,
Jul 15, 2009, 7:09:50 AM7/15/09
to

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.

--
_________________________________________________________________
Peter Breitfeld, Bad Saulgau, Germany -- http://www.pBreitfeld.de

Albert Retey

unread,
Jul 16, 2009, 8:05:15 AM7/16/09
to
Hi,

> 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

Szabolcs

unread,
Jul 16, 2009, 8:17:17 AM7/16/09
to
On Jul 15, 2:09 pm, Peter Breitfeld <ph...@t-online.de> wrote:
> 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.
>

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.

Simon

unread,
Jul 16, 2009, 8:18:47 AM7/16/09
to
Hi Peter,

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

Valeri Astanoff

unread,
Jul 17, 2009, 5:01:03 AM7/17/09
to


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

Leonid Shifrin

unread,
Jul 18, 2009, 4:43:15 AM7/18/09
to
Hi Peter,

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

Peter Breitfeld

unread,
Jul 18, 2009, 4:44:50 AM7/18/09
to

With the help of Valerie Astanoff I ended up with the following
function, which tests, if f is not a Function and sends an Abort[] in
this case:


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[]]

ADL

unread,
Jul 18, 2009, 8:00:30 AM7/18/09
to
Another possibility is to define a "question" function like this:

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

ADL

unread,
Jul 19, 2009, 7:13:20 AM7/19/09
to
Actually, after some work, I found a solution which appears more
reliable (but who knows...):

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:

Peter Breitfeld

unread,
Jul 20, 2009, 5:59:07 AM7/20/09
to

Yours is a fine solution, but why do you need AtomQ?

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.

0 new messages