Power in depth: f⍣k
Power in depth: f⍣k
#
When the power operator, ⍣
, is given an integer as the right operator, it is a very simple: (f⍣k)Y
is simply f f f … f f Y
. In its dyadic form, it uses the left argument unchanged every time: X(f⍣k)Y
is X f X f X f … X f X f Y
.
The only thing to look out for is that the count (k
) must be separated from the argument, either by naming, or with parenthesis, or by a monadic function (often ⊢
). Note that k
may be 0, which can be used for “branch-less” conditionals, like replacing one value with another on a condition:
3⊣⍣('a'='b')⊢4
3⊣⍣('b'='b')⊢4
4
3
In the same vein, you can also use it to perform an action conditionally:
{⎕←'yup1'}⍣('b'='b')⊢4
{⎕←'yup2'}⍣('a'='b')⊢4
'done'
yup1
4
done
However, ⍣k
can be quite limited. For example, it doesn’t give you the intermediary results. If we need the intermediate results, we could try something like this:
2{list,←⍺×⍵}⍣5⊢list←10
list
10 20 40 80 160 320
However, this approach has a subtle problem. Behold:
⎕←{list,←⊂⍵}⍣3⊢list←⊂'Yes'
list
┌─────────┐ │┌───────┐│ ││┌─────┐││ │││┌───┐│││ ││││Yes││││ │││└───┘│││ ││└─────┘││ │└───────┘│ └─────────┘
┌───┬─────┬───────┬─────────┐ │Yes│┌───┐│┌─────┐│┌───────┐│ │ ││Yes│││┌───┐│││┌─────┐││ │ │└───┘│││Yes│││││┌───┐│││ │ │ ││└───┘│││││Yes││││ │ │ │└─────┘│││└───┘│││ │ │ │ ││└─────┘││ │ │ │ │└───────┘│ └───┴─────┴───────┴─────────┘
The problem here is that the argument and all results must be scalar. Observe:
⎕←2{list,←⍺×⍵}⍣5⊢list←10 11
list
320 352
10 11 20 22 40 44 80 88 160 176 320 352
We can resolve this by either disclosing it after the concatenation {⊃list,←⊂⍺×⍵}
or use a “concatenate-the-enclosed” function for the modified assignment:
⎕←2{list,∘⊂←⍺×⍵}⍣5⊃list←⊂10 11
list
320 352
┌─────┬─────┬─────┬─────┬───────┬───────┐ │10 11│20 22│40 44│80 88│160 176│320 352│ └─────┴─────┴─────┴─────┴───────┴───────┘
Now we can write an operator that works like ⍣
but returns all the intermediaries:
Pow←{⍺←⊢ ⋄ r⊣⍺ ⍺⍺{r,∘⊂←⍺ ⍺⍺ ⍵}⍣⍵⍵⊃r←⊂⍵}
2×Pow 5⊢10 11
┌─────┬─────┬─────┬─────┬───────┬───────┐ │10 11│20 22│40 44│80 88│160 176│320 352│ └─────┴─────┴─────┴─────┴───────┴───────┘
Going back to 2{list,∘⊂←⍺×⍵}⍣5⊃list←⊂10 11
, let’s study that in more detail. First we add the original input as a scalar: list←⊂10 11
. However, later, with list,∘⊂←
we only use the enclose as part of the amendment of list. The pass-through of an assignment is always whatever is on the right of ←
, which is why we don’t need to disclose. We could have written ⊃list,←⊂
, too.
In the operator version, the first thing is ⍺←⊢
. In a dfn and dop, this is a special statement which is only executed if the function is called monadically:
{⍺←⎕←'hello' ⋄ ⍺ ⍵}'world'
'hi'{⍺←⎕←'hello' ⋄ ⍺ ⍵}'world'
hello ┌─────┬─────┐ │hello│world│ └─────┴─────┘
┌──┬─────┐ │hi│world│ └──┴─────┘
Note that the side effect of printing ‘hello’ only happened in the monadic case.
⍺←⊢
literally assigns the function ⊢
to ⍺
. So, while normally ⍺
and ⍵
are arrays, ⍺
can be a function in this special case. It works with any function, not just ⊢
, too:
{⍺←! ⋄ ⍺+⍵}4 ⍝ works with any function!
2{⍺←! ⋄ ⍺+⍵}4
24
6
This is a convenient way to write ambivalent functions. The inner function is simply the expression we came up with before: {r,∘⊂←⍺ ⍺⍺ ⍵}⍣⍵⍵
. However, since the function we’re actually applying doesn’t have a name, we have to pass it in as ⍺⍺
, so the operand to ⍣
is actually another operator. That’s why it has the ⍺⍺
of the outer operator on its left, to pass in the function:
Pow←{⍺←⊢ ⋄ r⊣⍺ ⍺⍺{r,∘⊂←⍺ ⍺⍺ ⍵}⍣⍵⍵⊃r←⊂⍵}
We could also have named it, and used the name:
Pow2←{⍺←⊢ ⋄ f←⍺⍺ ⋄ r⊣⍺ {r,∘⊂←⍺ f ⍵}⍣⍵⍵⊃r←⊂⍵}
2×Pow2 5⊢10 11
┌─────┬─────┬─────┬─────┬───────┬───────┐ │10 11│20 22│40 44│80 88│160 176│320 352│ └─────┴─────┴─────┴─────┴───────┴───────┘
A couple of more things worth mentioning about ⍣k
. The inverse ⍣¯1
is quite nifty, and can make things easy that are otherwise complicated. Maybe the most well-known example is ⊥⍣¯1
. The problem is that to convert a number to a given base, ⊤
requires you to tell it how many digits in that base you want. For example,
2 2 2 2 2 2⊤10 ⍝ 10 in 6-bit binary
0 0 1 0 1 0
However, the other way, ⊥
just reuses a single base for all digits:
2⊥0 0 1 0 1 0
10
This means that the inverse of ⊥
also reuses a single base for “all” digits (that is, as many as needed):
2⊥⍣¯1⊢10
1 0 1 0
⍣
can also invert non-trivial functions:
celsius2farenheit←32+1.8∘×
celsius2farenheit 20
celsius2farenheit⍣¯1⊢ 68
68
20
It also works with non-numeric things:
'a',⍣¯2⊢'aaaaa'
aaa
Here, we did the inverse of prepending “a” twice. That is, we removed two “a”s. If we try to give it something that doesn’t begin with two “a”s, we get an error:
'a',⍣¯2⊢'abaaa' ⍝ DOMAIN ERROR
DOMAIN ERROR
'a',⍣¯2⊢'abaaa' ⍝ DOMAIN ERROR
∧
Finally, let’s introduce the concept of “Under”. Sometimes, we want to perform an action while the subject of that action is in a temporary state maintained for the duration of the action. For example, we perform surgery under anaesthesia, and drive under the influence (don’t!). ⍣
can make this very readable by defining the temporary action as an invertible function: Temp⍣¯1⊢Main Temp argument
. We can define such an operator:
Under←{⍵⍵⍣¯1 ⍺⍺ ⍵⍵ ⍵}
+/Under⍟3 4 ⍝ multiplication is summation under logarithm
12
If you know the @
operator, it can be used in combination:
'_'@2⊢'hello' ⍝ put an underscore *at* position 2
h_llo
'_'@2Under⌽'hello' ⍝ put an underscore *at* position 2 while reversed, that is, 2nd last
hel_o