Group Abstract Group Abstract

Message Boards Message Boards

0
|
3.2K Views
|
5 Replies
|
3 Total Likes
View groups...
Share
Share this post:

How to use Goto function

Posted 2 years ago

I'm having a bit of a syntax problem. I'm trying to figure out how the Goto function works. here is what I have as a simple test case:

i = 0;

Label[start];
i ++;
If[i == 20, Goto[end], Goto[start]];

Label[end];
Print[i]

this should increment i until it equals 20, then print it. However, when I try to run this I get the error message "Goto: nolabel: label start not found". It seems that it can't find the start label, even though it is right there.

I do not understand why it is not working, I followed the syntax in the documentation, and it doesnt seem like it's really any different than the Goto statement in other programming languages...

POSTED BY: Shion Arita
5 Replies
Posted 2 years ago

The question I have is, where can I learn this stuff? Where can I learn how exactly the parser works? Where can I learn exactly how compound expressions work?

The challenges you describe are very common for folks starting out with Mathematica. Let's try to understanding parsing.

Mathematica is actually very similar to Lisp in terms of code syntax. An expression like myFunc[a,b,c] is equivalent to something like (myFunc a b c) in Lisp. And just like Lisp, valid Mathematica code will already have the shape of an abstract syntax tree. This is a major contrast with languages like C.

Now, typical Mathematica code may not look like a tree, but that's because there is a ton of syntactic sugar available to use. The semi-colon is not a line-terminator, nor does it serve as an output suppressor--it's actually infix form for CompoundExpression just like the plus sign, +, is infix for Plus. The suppression of output is just due to the fact that threre will be a Null in the last spot of the CompoundExpression, and raw Nulls don't get displayed by the front end.

Hold and FullForm are your friends here. FullForm shows you what code is going to be executed by the back end after the syntactic sugar has been dealt with. Hold keeps expressions from being evaluated. So, if you ever want to see what your code really says, you can wrap it with FullForm[Hold[...your code...]]. So, let's look at

FullForm[Hold[
  myFunction[] := (
    a = b + c; 
    d = a - 1;
  )]]

We get Hold[SetDelayed[myFunction[], CompoundExpression[Set[a, Plus[b, c]], Set[d, Plus[a, -1]], Null]]]

What if we didn't have the parentheses?

FullForm[Hold[
  myFunction[] :=
   a = b + c;
  d = a - 1;]]

Hold[CompoundExpression[SetDelayed[myFunction[], Set[a, Plus[b, c]]], Set[d, Plus[a, -1]], Null]]

So, the main issue here is NOT one of parentheses being required for function definitions, but instead one of simple precedence. Infix ; has lower precedence than infix :=. This is the only use for parentheses--they don't otherwise have any meaning. Also notice that newlines get removed. Newlines have no meaning either (although, aggravatingly, they can break Goto as you discovered).

If that Null looks weird, it's just because that's how the sugar of ; is defined to work. A trailing ; will get a Null inserted after it. This is how we get the effect of suppressing output. The "result" of a CompoundExpression is the result of its final term. so, something; evaluates to Null, which is a completely valid output value, but raw Null just doesn't display in the front end.

One other "trick". The front end can help you find the tree structure. If you put your cursor somewhere in an expression and tap Control-. (I'm using a Mac, but the command is called "Extend Selection" and you can find it in the Edit menu), the selection will expand to include the next "level" of the underlying syntax tree. So, for your myFunction code, try the following with both forms (the one with parentheses and the one without): Select the "b" and repeatedly tap Control-..

That's a lot for now. Happy to answer other specific questions that come up as you play with this. As for where you can learn this stuff,

POSTED BY: Eric Rimbey
Posted 2 years ago

I'll try to answer your question, but first...

DO NOT USE Goto.

I don't know why they added Goto to the language, but you don't need it and it has just led to this specific problem coming up repeatedly.

So, before I answer your question, let me remind you...

DO NOT USE Goto EVER, EVEN AFTER I EXPLAIN HOW TO FIX THIS

I can't even really specify exactly the sequence of events that leads to this, but it has something to do with how the front end parses an expression and then whether it thinks the expression containing the Goto and Label are in the same CompoundExpression (or some containing CompoundExpression higher up the syntax tree). In your case, there's no question that they really are in the same CompoundExpression, but somewhere along the line between front-end parsing and back end evaluation, it got confused and can't determine that the Goto and Label are in the same CompoundExpression.

Here's how you can fix it, but first let me remind you...

IF YOU THINK YOU NEED TO USE Goto IN YOUR CODE, YOU ARE WRONG--YOU DO NOT EVER EVER EVER NEED TO USE Goto

Okay, you need to help the front end (or back end, wherever the confusion comes from) not get confused. You can do this by:

  • Delete all newlines. This way the CompoundExpression will be on one line. Now, the front end actually tries to displays long expressions nicely, so you will see some wraparound, and it may end up looking exactly the same as what you started with. But anyway, newlines cause trouble here.
  • Okay, now we're getting really crazy. Wrap your whole expression in ReleaseHold[Hold[...]]:

    ReleaseHold[Hold[
      i = 0;
      Label[start];
      i++;
      If[i == 20, Goto[end], Goto[start]];
      Label[end]; Print[i]]]
    

    I honestly don't know if that's guaranteed to always work, but it does work for your code. Somehow this interrupts execution in a way that allows the parsing to work correctly. Or something. Shrug.

  • You can also try just wrapping your expression in parentheses. This is another syntax/structure hint to the parser, and it did work on your code, but again, I'm reallly not sure if this is a guaranteed fix.

Now, please forget everything I told you and forget that Goto exists.

POSTED BY: Eric Rimbey
Posted 2 years ago

Thanks a lot, Eric!! Your explanation has gotten me past most of the issues I was having with understanding how things work in Wolfram language. This was extremely helpful. Seeing a lot of these things as infix 'sugar' on top of the lisp-like expression structure really explains what is happening in a way that I haven't seen in any other material I've found about this.

Henrik, your link also has a lot of useful things, thanks!

POSTED BY: Shion Arita
Posted 2 years ago

Thanks a lot for helping me here!

I know that using Goto is 'bad', and I don't intend to use it except in the very few cases where it significantly simplifies the program. I was a bit worried that I was going to get the unhelpful "just don't use Goto", so seriously, thank you for actually answering the question!

I am very new to wolfram language, and really only have experience with lower level, imperative programming languages like C. I actually went down the Goto rabbit hole because I was trying to work around/debug other problems I was having with the syntax, and write something where at least I could test exactly what the program was doing. I'm having some pretty fundamental issues with understanding how to deal with control flow, and a lot of the syntax. And I've found the documentation to be very unhelpful.

For example, it took me a very long time (and was ultimately bailed out by a stackoverflow comment) to figure out the full structure syntax for functions. For example, I wanted to write a function that takes zero arguments and executes multiple statements. To give a toy example:

myFunction[] := (
    a = b + c;
    d = a - 1;
)

the fact that parentheses are what's required here (and not, say, square brackets) is not in the documentation for functions. And the fact that the expressions need to be terminated with semicolons and not new lines is not in there (i thought semicolons only served to suppress displaying the output of that line). And (though this one wasn't hard to figure out) the fact that the empty square brackets have to be there to define a zero arg function isn't documented either. Or, if it is, I have no idea where to look.

The question I have is, where can I learn this stuff? Where can I learn how exactly the parser works? Where can I learn exactly how compound expressions work?

POSTED BY: Shion Arita
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard