10

Here is what I tried to do:

Scan[Function[x,
  Scan[Function[y,
    If[y == 2, Return[]];
    (* Do something useful *) Print[y]],
   x]],
 {{1, 2, 3}, {4, 5, 6}}]

My intention was that the Return[] exited from the innermost enclosing pure function (having the parameter y). Instead, it terminated execution of the innermost enclosing Scan and proceeded to the next iteration of the outermost Scan.

1 4 5 6

The documentation for Return says:

Return exits only the innermost construct in which it is invoked

I do not see why the innermost Scan is considered the innermost enclosing construct here. If, CompoundExpression and Function look like more inner constructs.


Question 1: Could you give a more clear explanation of what precisely Return does?


After I realized that Return does not do what I want here, I looked for workaround, and found several ones:

(a) I can restructure the body of the innermost pure function:

Scan[Function[x,
  Scan[Function[y,
    If[y != 2,
     (* Do something useful *) Print[y]]
    ],
   x]],
 {{1, 2, 3}, {4, 5, 6}}]

In this case it looks straighforward, but becomes messy if I have more nested control flow operators and multiple points where I might need to exit.

(b) I can use infamous Label and Goto constructs:

Scan[Function[x,
  Scan[Function[y,
    Module[{exit},
     If[y == 2, Goto[exit]];
     (* Do something useful *) Print[y];
     Label[exit];
     ]], 
    x]],
 {{1, 2, 3}, {4, 5, 6}}]

(c) I can use Throw and Catch constructs:

Scan[Function[x,
  Scan[Function[y,
    Module[{exit},
     Catch[
      If[y == 2, Throw[Null, exit]];
      (* Do something useful *) Print[y],
      exit]]],
   x]],
 {{1, 2, 3}, {4, 5, 6}}]

Question 2: Which of them would you prefer? Or can you suggest a better way to do this?

Vladimir Reshetnikov
  • 7,213
  • 27
  • 75

3 Answers3

12

You can specify the evaluation of which construct should be stopped by Return by providing the second argument (undocumented?). For example,

Scan[Function[x,
  Module[{},
   Print[x];
   Return[$Failed, Module];
   Print[-x]]],
 {1, 2, 3}]

or

Scan[Function[x,
  Print[x];
  Return[$Failed, CompoundExpression];
  Print[-x]],
 {1, 2, 3}]
TauMu
  • 471
  • 3
  • 6
7

It's hard to reply without larger context, but if you are not restricted to use pure functions, then one option would be to use the pattern-defined overloaded function instead:

ClearAll[fun];
fun[2] := Null;
fun[x_] := ((*Do something useful*)Print[x])

Then, you just write:

Scan[Function[x, Scan[fun, x]], {{1, 2, 3}, {4, 5, 6}}]

In fact, you can as well define fun at run-time, if you need.

As to Return, I can recommend this, and particularly this discussions for more details on how it works.

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
2

I would use Catch and Throw if pressed to choose, without the 'exit' :

Scan[Function[x,
  Scan[Function[y,
    Catch[If[y == 2, Throw[Null]];
     (*Do something useful*) Print[y]]
    ],
   x]],
 {{1, 2, 3}, {4, 5, 6}}]

or simply,

Scan[Function[x,
  Scan[Function[y,
    If[y == 2, Null,
     (*Do something useful*) Print[y]]
    ],
   x]],
 {{1, 2, 3}, {4, 5, 6}}]
Chris Degnen
  • 30,927
  • 2
  • 54
  • 108