Question

As title says, I don't understand why f^:proposition^:_ y is a while loop. I have actually used it a couple times, but I don't understand how it works. I get that ^: repeats functions, but I'm confused by its double use in that statement.

I also can't understand why f^:proposition^:a: y works. This is the same as the previous one but returns the values from all the iterations, instead of only the last one as did the one above.

a: is an empty box and I get that has a special meaning used with ^: but even after having looked into the dictionary I couldn't understand it.

Thanks.

Was it helpful?

Solution 2

f^:proposition^:_ is not a while loop. It's (almost) a while loop when proposition returns 1 or 0. It's some strange kind of while loop when proposition returns other results.

Let's take a 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 (v y) = 0
32
(f^:v^:_) 2
32
(f^:v^:_) 5
20
(f^:v^:_) 21   NB. (f^:0) y
21

This is what's happening: every time that v y is 1, (f^:1) y is executed. The result of (f^:1) y is the new y and so on.

  • If y stays the same for two times in a row → output y and stop.
  • If v y is 0→ output 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 2/0 instead of 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 "strange" loops by playing with v. (It can even return negative integers, to use the inverse of f).

OTHER TIPS

Excerpted and adapted from a longer writeup I posted to the J forums in 2009:

while =:  ^:break_clause^:_

Here's an adverb you can apply to any code (which would equivalent of the loop body) to create a while loop. In case you haven't seen it before, ^: is the power conjunction. More specifically, the phrase f^:n y applies the function f to the argument y exactly n times. The count n maybe be an integer or a function which applied to y produces an integer¹.

In the adverb above, we see the power conjunction twice, once in ^:break_clause and again in ^:_ . Let's first discuss the latter. That _ is J's notation for infinity. So, read literally, ^:_ is "apply the function an infinite number of times" or "keep reapplying forever". This is related to a while-loop's function, but it's not very useful if applied literally.

So, instead, ^:_ and its kin were defined to mean "apply a function to its limit", that is, "keep applying the function until its output matches its input". In that case, applying the function again would have no effect, because the next iteration would have the same input as the previous (remember that J is a functional language). So there's no point in applying the function even once more: it has reached its limit.

For example:

   cos=:  2&o.   NB. Cosine function
   pi =:  1p1    NB. J's 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 keep applying cosine until the answer stops changing: cosine has reached its fixed point, and more applications are superfluous. 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 a function to its limit. OK, what about ^:break_condition? Again, it's the same concept: apply the function on the left the number of times specified by the function on the right. In the case of _ (or its function-equivalent, _: ) the output is "infinity", in the case of break_condition the output will be 0 or 1 depending on the input (a break condition is boolean).

So if the input is "right" (i.e. processing is done), then the break_condition will be 0, whence loop_body^:break_condition^:_ will become loop_body^:0^:_ . Obviously, loop_body^:0 applies the loop_body zero times, which has no effect.

To "have no effect" is to leave the input untouched; put another way, it copies the input to the output ... but if the input matches the output, then the function has reached its limit! Obviously ^:_: detects this fact and terminates. Voila, a while loop!


¹ Yes, including zero and negative integers, and "an integer" should be more properly read as "an arbitrary array of integers" (so the function can be applied at more than one power simultaneously).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top