Excerpt and adapted from a longer post that I posted to the J-forum in 2009 :
while =: ^:break_clause^:_
Here's an adverb that you can apply to any code (which is equivalent to a loop body) to create a while loop. If you have not seen this before, ^: is the power loop. More specifically, the phrase f^:ny applies the function f to the argument y exactly n times. The counter n can be an integer or the function that applies to y gives an integer¹.
In the above adverb, we see that the power is combined twice, once in ^:break_clause and again in ^:_ . Let them discuss the latter first. This _ is the notation J for infinity. So, read literally, ^:_ - "apply the function an infinite number of times" or "continue re-applying forever." This is due to the while-loop function, but it is not very useful if applied literally.
So, instead, ^:_ and his relatives were defined as meaning "apply the function to its limit," that is, "continue to use the function until its output matches its input." In this case, using the function again will have no effect, because the next iteration will have the same input as the previous one (remember that J is a functional language). So, there is no point in applying this function again: it has reached its limit.
For instance:
cos=: 2&o. NB. Cosine function pi =: 1p1 NB. J notation for 1*pi^1 analogous to scientific notation 1e1 cos pi _1 cos cos cos pi 0.857553 cos^:3 pi 0.857553 cos^:10 pi 0.731404 cos^:_ pi NB. Fixed point of cosine 0.739085
Here we continue to use cosine until the answer stops changing: cosine has reached its fixed point, and more applications are redundant. We can visualize this by showing the intermediate steps:
cos^:a: pi 3.1415926535897 _1 0.54030230586813 ...73 more... 0.73908513321512 0.73908513321
So ^:_ applies the function to its limit. Alright, what about ^:break_condition ? Again, this is the same concept: apply the function on the left the number of times indicated by the function on the right. In the case of _ (or its function equivalent, _: output is "infinite"; in the case of break_condition output will be 0 or 1 depending on the input (the break condition is Boolean).
So, if the input is “right” (that is, processing is completed), then break_condition will be 0 , from where loop_body^:break_condition^:_ will become loop_body^:0^:_ . Obviously loop_body^:0 applies a loop_body time of loop_body , which has no effect.
To "have no effect", you need to leave the entrance intact; in another way, it copies the input signal to the output ... but if the input matches the output signal, then the function reaches its limit! Obviously, ^:_: detects this fact and ends. Voila, loop!
¹ Yes, including zero and negative integers, and the "integer" should be more correctly read as "an arbitrary array of integers" (therefore, the function can be used simultaneously with several powers).