One way to write a function with argument checking is to write subroutines for your function f
that handles the actual calculation, and then do the argument checking in the main routine for f
.
As a highly simplified example, let's call the subroutines for f
intF
:
intF[x_Integer] := x + 1
intF[x_ /; ArrayQ[x, _, IntegerQ]] := x + 1
so that f
should only work for an integer or an array of integers.
We can then define error messages that f
can emit:
f::nlst = "The argument `1` is not an integer or an array of integers.";
From that, you can write f
like this:
f[x__] := Module[{nargs, res},
nargs = Length[{x}];
res /; If[nargs == 1,
If[Head[res = intF[x]] =!= intF,
True,
Message[f::nlst, x]; False],
Message[f::argx, f, nargs]; False]]
The main point here is the use of Condition[]
(/;
) to do the argument checking; recall that in the expression expr /; test
, test
should be something that evaluates to True
or False
, and expr
will only then be evaluated.
In this example, the first check is a simple argument count, done by checking if {x}
has length 1 (i.e. f
was only passed one argument). If the test fails, then the part Message[f::argx, f, nargs]; False
gets evaluated, and since the last result is False
, we get no evaluation of res
.
Note, however, that I did not define the message f::argx
. In this case, the message text is taken from General::argx
.
If the check of the argument count is passed, we get to the inner conditional. In there, we evaluate Head[res = intF[x]] =!= intF
. Two things are done here: the result of the subroutine intF[x]
is assigned to res
, after which it is checked if evaluation occurred (i.e. the head of res
is no longer intF
). If this test is passed, we get the ultimate result True
for the condition, and thus the previously evaluated res
is returned. Otherwise, Message[f::nlst, x]; False
gets evaluated.
With this, f[3]
and f[{{1}, {2}}]
will evaluate as usual, but f[2.]
and f[{{5, 6}, {4}}]
will throw the message f::nlst
, while f[1, 9]
will throw the message f::argx
.
Compile
your function, and you will get what you want, I suppose. $\endgroup$