Power in depth: f⍣g#

with a function right operand is conceptually simple, but has some gotchas to be aware of. For this section, we’ll call the left operand f and the right operand g, that is, we’re applying f⍣g. When the derived function is used dyadically, it is just as if it was used monadically with the left argument bound to f. That is, X f⍣g Y is exactly the same as X∘f⍣g Y, so we only need to discuss the monadic case. The high-level view is that f⍣g applies f until f g .

Now, what exactly does that mean?

We start by applying f Y and its result is used as left argument to g. The right argument to g is the original Y. g must then return 0 or 1. If g returns 1 it means we’re done, and the result will be the newly found value, f Y. If g returns 0 then we conceptually set Y←f Y and start over. For example, we can find a “fix-point” by having g←=. If we take 10 and divide it by 2 over and over until it doesn’t change any more, we’ll end up with… 0:

2÷⍨⍣=10
0

The power (no pun) of is of course that you can use any functions as operands. You also don’t have to use both arguments of g. Often, you just want to repeat an action until a condition on the generated value is fulfilled.

Let’s say we want to use to find the first power of 2 larger than 100. That is, double 1 until it exceeds 100. Remember that the newly generated value (the one we’re interested in) is the left argument of g. If you use the right argument of g, you’ll have applied f one more time than needed because your stop condition hinges on the previous value, but the current value has already advanced one more step.

2×{100<}1
128

Another example. Given a string, keep dropping characters from the front until it is a palindrome.

IsPal⊢≡⌽
Palify{1{IsPal }(~IsPal )}
Palify¨'otto' 'risotto'
┌────┬────┐
│otto│otto│
└────┴────┘

Here, 1↓⍣{IsPal ⍺} is the same as what we’ve done before, but we only apply it if the argument isn’t already a palindrome. The “if” is expressed with and an array right-operand.

can be your friend when you want to test each one of a set until you find a good one, without having to test all of them. You can also use it to loop indefinitely until some outside condition tells you to stop. In that case, you’d use neither of the arguments of g. Sometimes, you don’t care about the argument(s) to f either, you just need a dummy argument to get the loop going.

For example, here is an expression to collect lines of text from the user until they enter a blank line:

¯1text{text,}{''}text0⍴⊂''

And here is one that neither uses the arguments of f, nor of g; output random numbers 1…10 until we roll a 6:

{}{?10}{6=?6}
4
4
1
5
2
10
5
8
4
2

It doesn’t output the condition roll, just some random number each time. Here is one that keeps rolling until it gets a 6:

{}{?10}{6=}
8
10
10
1
10
9
10
10
9
9
10
1
6

Here’s a trick using f⍣g. Sometimes, we can have a nested list of lists of lists, for example, because we got some JSON data, but we really want to use APL’s array capabilities, so we want to convert this to a proper multi-dimensional array.

For example, we get the JSON data [[[5,22,13,18],[9,19,16,11],[4,2,12,20]],[[8,6,17,1],[10,24,15,14],[21,23,7,3]]] which we can convert to an APL array:

⎕JSON'[[[5,22,13,18],[9,19,16,11],[4,2,12,20]],[[8,6,17,1],[10,24,15,14],[21,23,7,3]]]'
┌─────────────────────────────────┬────────────────────────────────┐
│┌──────────┬──────────┬─────────┐│┌────────┬───────────┬─────────┐│
││5 22 13 18│9 19 16 11│4 2 12 20│││8 6 17 1│10 24 15 14│21 23 7 3││
│└──────────┴──────────┴─────────┘│└────────┴───────────┴─────────┘│
└─────────────────────────────────┴────────────────────────────────┘

But we want a 2-by-3-by-4 array. How would we do this in a general fashion, without querying the depth?

⎕JSON'[[[5,22,13,18],[9,19,16,11],[4,2,12,20]],[[8,6,17,1],[10,24,15,14],[21,23,7,3]]]' 
 5 22 13 18
 9 19 16 11
 4  2 12 20

 8  6 17  1
10 24 15 14
21 23  7  3

So ↑⍣≡ is a neat idiomatic expression which is worth remembering. The other way, converting a high-rank array to lists of lists isn’t as neat, because you can keep applying and it will just add more nesting. What can we come up with for that? Since starts at the “bottom”, we can just keep going until we have a vector. However, if we know we’ll get one enclosure too much, we can just disclose once when done.

⊃↓{0≡≢⍴}2 3 4⍴⍳24
┌────────────────────────────┬─────────────────────────────────────┐
│┌───────┬───────┬──────────┐│┌───────────┬───────────┬───────────┐│
││1 2 3 4│5 6 7 8│9 10 11 12│││13 14 15 16│17 18 19 20│21 22 23 24││
│└───────┴───────┴──────────┘│└───────────┴───────────┴───────────┘│
└────────────────────────────┴─────────────────────────────────────┘