How to implement try/catch/end try in Mathematica in the most simple way?
You could do
f[x_, y_] := Check[x/y, $Failed]
f[1, 0]
During evaluation of Power::infy: Infinite expression 1/0 encountered.
$Failed
In this way you can pass the $Failed
to the caller and react to it, instead of passing the default of ComplexInfinity
(which is useful in its own way).
Maybe something like this?
f[x_, y_] := Module[{}, Quiet@Check[x/y, Throw["I give up, bad input"]]];
f[1, 0]
(* Throw::nocatch : Uncaught Throw[I give up, bad input] returned to top level. *)
Here's a simple way to do that. First define something to validate your output and which will Throw
a tag if invalid. Then Catch
that:
validateResp // Clear
validateResp[resp_, validator_, error_: Automatic] :=
If[! TrueQ[validator@resp],
Throw[resp, Replace[error, Automatic :> $tryCatchTag]],
resp
];
tryCatch // Clear
SetAttributes[tryCatch, HoldFirst];
tryCatch[
expr_,
error : _String | Verbatim[Blank][] : "BadValue",
handler : Except[_String | Verbatim[Blank][]] : (#2 &),
validator : Except[_String | Verbatim[Blank][]] : (Length[$MessageList] == 0 &)
] :=
Block[{$tryCatchTag = error},
Catch[
validateResp[expr, validator, error],
error,
handler
]
]
You'd use it like this:
tryCatch[
1/0
]
(* Message: Power::infy: Infinite expression 1/0 encountered. *)
(* Out: "BadValue" *)
Unfortunately there's no global sense of "if an error occurred" so by default my validator
just checks if any messages were generated when evaluating, but this can be anything. You can also put a deeper validateResp
in there if you want. You can also easily throw your own errors and catch anything like:
tryCatch[
If[! TrueQ[n > 2],
validateResp[False, False &, "BadN"],
1/0
],
_
]
"BadN"
Which if the first test passed would give you
tryCatch[
If[False,
validateResp[False, False &, "BadN"],
1/0
],
_
]
(* Message: Power::infy: Infinite expression 1/0 encountered. *)
(* Out: _ *)