0

I have an iterated computation running in a while loop, which is bound to fail at some point, at which point I want it to stop, e.g.

currentSolution = 0;
Block[{i = -3},
 While[i < 3,
  correction = 1/i;
  currentSolution += correction;
  i++;
  ];
 currentSolution
 ]

Of course in my actual application the computation is more complicated, I don't know ahead of time when it will fail, and the While condition depends on result too.

I want the While loop to stop at any error message, suppress Mathematica's messages and show my own.

Furthermore I want to be able to easily customise this, i.e. turn off the error checking completely or change the messages that are shown or that trigger the error.

For this I've written the general code:

Attributes[checkError] = {HoldFirst};
checkError[{expr_, failCode_}, myErrorMessage_, myErrorMessageParams_,
   messagesIgnored_, messagesNotShown_, messagesShown_] := 
 If[$CheckError === False, expr, 
  Quiet[Check[Quiet[expr, messagesIgnored], failCode;
    Message[myErrorMessage, myErrorMessageParams];
    Return[$Failed, Block]], messagesNotShown, messagesShown]]

and a more specific one that uses the above:

Attributes[checkError2] = {HoldFirst};
checkError2[expr_, params_] := 
 checkError[{expr, currentSolution = $Failed}, my::message, 
  params, $MessagesIgnored, $MessagesNotShown, $MessagesShown]

$CheckError = True;
$MessagesIgnored = {};
$MessagesNotShown = All;
$MessagesShown = {my::message, General::stop};
my::message = "Failed at `1`!";

which I would want to use as:

currentSolution = 0;
Block[{i = -3},
 While[i < 3,
  correction = checkError2[1/i, i];
  currentSolution += correction;
  i++;
  ];
 currentSolution
 ]

The intention is for this to show my::message and output $Failed.

There are some problems with this code though:

at the above it doesn't recognise the messages in messagesShown nor myErrorMessage:

enter image description here

When I explicitly copy {my::message, General::stop} into messagesShown in checkError these errors disappear and it outputs $Failed. When I do the same with my::message that also displays. But for instance replacing messagesShown with Evaluate@messagesShown does not work.

Another issue is that even if it worked, messagesIgnored would indeed be ignored by Check because the Quiet is inside, but they would also obviously not be shown, which is not what I want, that should be controlled by messagesNotShown and messagesShown. Unlike for Quiet there is no additional argument for Check that controls which messages not to check for.

How do I fix these issues and make this code work as intended?

Jansen
  • 1,223
  • 9
  • 17
  • @Alan No particular reason (but I just checked that with Module it gives the same error). – Jansen Nov 05 '18 at 15:15
  • @Alan What do you mean? I am Checking the errors that this code is supposed to encounter, while the errors that this code itself generates are actual errors that preventie it from functioning. – Jansen Nov 05 '18 at 16:16
  • https://reference.wolfram.com/language/ref/Check.html – Alan Nov 05 '18 at 18:23
  • @Alan Yes I know about Check, it's there in between two Quiets in my code checkError. Messages blocked by the inner Quiet are ignored by Check (but are also not printed obviously, which is not what I want), while the outer Quiet of course doesn't affect Check. If you are trying to say that Check already has all the functionality that I want then I don't see it. – Jansen Nov 05 '18 at 18:51
  • Do named message groups not meet your needs? Sorry if not. – Alan Nov 05 '18 at 20:41
  • @Alan, No, I want to for instance be able to Check for all messages except one or several. Quiet supports this with Quiet[...,All,notQuiet] but Check does not. But I also don't understand why the messages are not recognised in my code. – Jansen Nov 06 '18 at 08:31
  • Regarding the errors you get: The problem is that my::message evaluates to the string "Failed at `1`" before the HoldAll attribute from Quiet has a chance to prevent this. To work around this, you have to pass in the messages in some held form and then carefully insert them into Quiet, e.g. using, myQuiet[expr_,Hold[messages__]]:=Quiet[expr,{messages}], Attributes[myQuiet]={HoldFirst} where messages will be Hold[my::Message,…] – Lukas Lang Nov 10 '18 at 09:56
  • For the other part, you could use [Internal`HandlerBlock](https://mathematica.stackexchange.com/a/1545) to build your own Check-like function – Lukas Lang Nov 10 '18 at 10:05

0 Answers0