J: Why does `f ^: sentence ^: _ y` mean a while loop?

As the title says, I don't understand why f^:proposition^:_ y is a while loop. I actually used it a couple of times, but I don’t understand how this works. I get the ^: functions to repeat, but I'm confused by its double use in this expression.

I also can't understand why f^:proposition^:a: y works. This is the same as the previous one, but returns values ​​from all iterations, not just the last ones, like the previous ones.

a: is an empty field, and I get that it has a special meaning, used with ^: but even after studying the dictionary I could not understand it.

Thanks.

+4
source share
2 answers

f^:proposition^:_ not a while loop. It has an (almost) while loop when proposition returns 1 or 0 . This is some weird kind of while loop when proposition returns other results.

Take the simple monadic case.

 f =: +: NB. Double v =: 20 > ] NB. y less than 20 (f^:v^:_) 0 NB. steady case 0 (f^:v^:_) 1 NB. (f^:1) y, until (vy) = 0 32 (f^:v^:_) 2 32 (f^:v^:_) 5 20 (f^:v^:_) 21 NB. (f^:0) y 21 

This is what happens: every time vy 1 , (f^:1) y is executed. The result of (f^:1) y is the new y , etc.

  • If y remains unchanged for two consecutive times; exit y and stop.
  • If vy - 0 → exit y and stop.

So f^:v^:_ here works like double while less than 20 (or until the result doesn't change)

Let's see what happens when v returns 0 instead 1 0 .

  v =: 2 * 20 > ] (f^:v^:_) 0 NB. steady state 0 (f^:v^:_) 1 NB. (f^:2) 1 = 4 -> (f^:2) 4 = 16 -> (f^:2) 16 = 64 [ -> (f^:0) 64 ] 64 (f^:v^:_) 2 NB. (f^:2) 2 = 8 -> (f^:2) 8 = 32 [ -> (f^:0) 32 ] 32 (f^:v^:_) 5 NB. (f^:2) 5 = 20 [ -> (f^:0) 20 ] 20 (f^:v^:_) 21 NB. [ (f^:0) 21 ] 21 

You can have many kinds of "weird" loops playing with v . (It can even return negative integers, use the inverse of f ).

+3
source

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).

+5
source

Source: https://habr.com/ru/post/977590/


All Articles