1.) In a function definition, e.g.
f[a_Real, b_Integer, c_:False]:= Print["function f called with Real argument a=", a , ", b=", b , ", c=", c ];
the third parameter can be given a default value and it can be called with one less parameter. In the example the default is
f remains unevaluated, if the first parameter does not have Head
Real OR if the second one does not have Head
Integer. But for the third one there is no type checking:
(* Tests... *) f[1, 2, True] (* remains unevaluated because first argument is not Real *) f[1.0, 2, True] f[2.0 ,2 ] f[3.0, 3, 4]
All but the first test evaluate with the
2.) Another way of checking parameters uses property tests whose names usually terminate with a capital
StringQ and so on (there is nothing like
RealQ). Before the test function a question mark has to follow the Underline pronounced “blank”:
ClearAll[a,b,c,g]; g[ a_?InexactNumberQ , b_?IntegerQ , c_?BooleanQ ] := Print["function g called with Real argument a=", a , ", b=", b , ", c=", c ]; (* Tests.... *) g[1, 2, True] (* remains unevaluated: 1 is no Inexact number *) g[1.0, 2, True] (* evaluates with the Print statement *) g[2.0, 2] (* remains unevaluated: too few arguments *) g[3.0, 3, 4] (* remains unevaluated: 4 is not True or False *)
RealQ[x_] := (Head[x] === Real); be the equivalent for real arguments, akin to
IntegerQ for Integer arguments and
BooleanQ for True/False? How does it differ from
InexactNumberQ? If I ask Mathematica, it can’t decide whether
RealQ as defined above and
InexactNumberQ are the same thing, but for all examples I came up with, both returned the same result.
In the example for
g, only the second test is evaluated because all arguments match their associated property tests. All others remain unevaluated because of a mismatch – as expected.
3.) Yet another way of checking parameters uses property tests or even more complicate test procedures and the construct
/; after the underline, pronounced “provided that”. If one puts the parameter test conditions after the closing bracket of the parameter list, even relations between different parameters become possible: However, writing
b_/.(b>a) inside of the parameter list does not work, because
a is displayed blue or black instead of green, indicating no reference to parameters of the function but rather to another object (if it exists). The third alternative requires a bit more writing, but one can make more elaborate tests on the structure and content of the actual parameters:
ClearAll[a,b,c,h]; h[a_ , b_ , c_/;BooleanQ[c] (* the test for c involves no other parameter, so it may be done here *) ]/;InexactNumberQ[a] && IntegerQ[b] && b>a := (* test involving a and b must be after the bracket *) Print["function h called with Real argument a=", a , ", b=", b , ", c=", c ]; (* Tests... *) h[1, 2, True] (* remains unevaluated: 1st argument no Inexact number *) h[1.0, 2, True] h[2.0, 2, True] (* remains unevaluated because !b>a *) h[2.0, 3] (* remains unevaluated: too few arguments *) h[3.0, 4, 5] (* remains unevaluated: 4 is not True or False *)
In the tests, only in the second one,
h, is evaluated because all arguments match their associated property tests. All others remain unevaluated. The result of the tests is:
h[1, 2, True] function h called with Real argument a=1., b=2, c=True h[2., 2, True] h[2., 3] h[3., 4, 5]
How would one modify my function definition giving a default value for an argument at the end of the argument list such that a given argument matches only if it matches
BooleanQ in my example.