8
$\begingroup$

I tend to like programming in a style where I can be very explicit about the types of expressions. While Mathematica isn't and shouldn't be a strongly-typed language like Haskell, I think it would sometimes be helpful to define a function that will explicitly reject inputs of an incorrect type.

I'm aware I can do something like

f[x_List] := x + 1
In[39]:= f[1]

Out[39]= f[1]

In[40]:= f[{1, 1}]

Out[40]= {2, 2}

This will prevent the pattern from matching on invalid arguments, but it will just propagate the unevaluated expression forward in other computations. However, I'd like to sometimes give myself stronger guarantees. I would like a function that matches on all input expressions, and errors if they fail to match some pattern. And I'd like to do it, if possible, in a way that minimizes boilerplate. Is there already an idiomatic way to do this?

$\endgroup$
  • 3
    $\begingroup$ Something like f[x_List] := x+1; f[_]="Error"? $\endgroup$ – Fred Simons Mar 27 '17 at 18:43
  • $\begingroup$ @MichaelCurry: Please complete your sentences in your question. $\endgroup$ – David G. Stork Mar 27 '17 at 18:46
  • $\begingroup$ @FredSimons yeah, that works and is boilerplate-free. I'm kind of embarrassed I didn't think of it. You can have f[_] throw, abort, or something else. Would you mind posting it as an answer? $\endgroup$ – Michael Curry Mar 27 '17 at 18:49
  • $\begingroup$ Possible duplicates: (4636), (33884) $\endgroup$ – Mr.Wizard Mar 28 '17 at 1:50
13
$\begingroup$

With the definition

f[x_List] := x + 1

you create a substitution rule that can only be applied when the argument of f is a List. In all other cases the function remains unevaluated. If instead you want to see an error message, or maybe no output, or whatever, you have to define a substitution rule for f that is applied in all other cases. That is most easily done in the following way:

f[_] = "Whatever you want";

That this rule is not used for arguments being a List is due to the fact that Mathematica uses the most restrictive rule first; that is the rule with argument restricted to a List.

f[1]

(* "Whatever you want" *)

f[{1}]

(* {2} *)
$\endgroup$
  • 3
    $\begingroup$ To detect incorrect number of arguments (e.g. f[1,2,3]) one can use f[___] instead of f[_]. $\endgroup$ – Shadowray Mar 27 '17 at 21:03
11
$\begingroup$

In general there are multiple reasons why a function could fail and it would be better to know the specific reason--particularly if it has been some time since the code was written.

See the documentation for Message

Clear[f]

f[x_] /; If[Head[x] === List, True,
   Message[f::arg, x]; False] := x + 1

f::arg = "The argument `1` is not a list.";

f[{1, 1}]

(*  {2, 2}  *)

f[1]

(*  f::arg: The argument 1 is not a list.

f[1]  *)
$\endgroup$
  • $\begingroup$ It seems you forgot to remove the first occurrence of f::arg = "The argument 1 is not a list.";. $\endgroup$ – anderstood Mar 27 '17 at 19:39
  • 1
    $\begingroup$ @anderstood - it is not a typo. See the documentation for Message under its "Details". The `1` is a placeholder for the first argument passed to Message Here, that passed argument is x which coincidentally has the value 1 $\endgroup$ – Bob Hanlon Mar 27 '17 at 19:48
  • $\begingroup$ Oh I see. Sorry. Luckily I did not edit your answer! $\endgroup$ – anderstood Mar 27 '17 at 20:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.