Essays/control error

From J Wiki
Jump to navigation Jump to search

When working with a long definition (perhaps while transcribing an algorithm from an implementation in some other language), it can be difficult to figure out where you have gone wrong when you get a "[Vocabulary/ErrorMessages#controlload|control error]" error message.

And it's difficult to ask for help here. Other people are not going to know what you intended, the definition is large, and at this stage of the game you're trying to get something working so you can better understand the important parts of the algorithm. (If you have time, once you have a transcribed algorithm working, you would typically examine how it works in small test cases so you can rewrite it in a way that's easier to read and/or easier to understand and/or more efficient.)

Ideally, the J editing environment would provide hints to help locate typos in sprawling control structures. But, until one of us gets around to implementing something like that, here's a quick mechanism:

badlines=: {{
  tokens=. ;: y
  starts=. tokens e. ;:'for.if.select.try.while.whilst.'
  nesting=. +/\ starts - tokens e. ;:'end.'
  min=. <./nesting
  if. min<0 do. mins=. (-1+i.|min)+/1 0 else. mins=. i.0 2 end.
  lines=. I.tokens e. ;:LF
  p0=. lines I. I. +/mins E."1 nesting
  p1=. lines I. I. (i.#nesting) e. nesting i: 1+i.0>.{:nesting
  problems=. ~./:~p0,p1
  over=. problems e. p0
  under=. problems e. p1 
  marker=. ' -+='{~ under+2*over
  (":,.problems),.marker,.' ',.>problems { cutLF y
}}

Here, y is a noun representing the body of code you're trying to get working. For example, given some horrible definition like:

example=: {{
  if. y=t do.
    if.*/isnull K t do.
    end.
  end.
  if. notnull k do.
  end.
  if. e do.
    while. p=y do.
      if. isnull s do.
        if. r M do.
          break.end.
      end.
      end.
      if. r s do.
        shift s continue. end.
      if. r f do.
        if. isnull N do.
        end.
      end.
    end.
    while. p~:t do.
      if. isnull s do.
        if. r M do.
          break.end.
      end.
      if. r s do.
        shift s continue. end.
      if. r f do.
        if. isnull N do.
        end.
      end.
      if. r N do.
        shift N continue. end.
      if. r M do.
        swap p,s break.end.
      if. p=y do.
      end.
    end.
  end.
  if. p=t do.
  else. echo 'done' end.
}}

We could replace the opening {{ with {{)n so that we could feed the result into badlines:

   badlines example
37+     end.                
40+   else. echo 'done' end.

Here, we discover that we have more closing 'end.' statements than we need. (There's actually only a single extra end. here, but we are not detecting it directly, since the computer is unable to figure out our intentions. Instead, we are seen the consequences of that extra end.: later control words show up as unbalanced. This characteristic is typical of computer error reporting -- the hidden problem typically precedes the multiple detectible problems.)

And, if we had indented consistently, we would have been able to quickly locate the problems.