Conversation started Jan 30, 2020 at 14:31.
Jan 30, 2020 14:31
Welcome to APL cultivation!
With no scheduled subject for today, please come with suggestions. Sam T suggested going over in more depth.
I could like that; I could also like "How to write operators".
Actually, we can conveniently fit that in.
The basic usage of is covered here.
Does anyone need a refresher, or can we go from there?
I can understand the basics
Jan 30, 2020 14:36
I get when ⍵⍵ is an integer; I don't grok when it's a function.
Right. When it is an integer, it is a very simple operator. (f⍣k)Y is simply f f f … f f Y
And the dyadic form uses the left argument unchanged every time: X(f⍣k)Y is simply 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 ).
@all That's all clear, right?
When k=¯1, I know it does the inverse function of f; is k<¯1 legitimate?
And is k=0 legitimate?
@JeffZeitlin Ah, good question. Yes. f⍣(-k) is f⍣¯1⍣(|k)
@JeffZeitlin Yes, it is a no-op, and if there's a left argument, it gets ignored.
You can use this for "branch-less" conditionals, like replacing one value with another on a condition:
Jan 30, 2020 14:41
So (f⍣0) X is X
⋄ 3⊣⍣('a'='b')⊢4
⋄ 3⊣⍣('b'='b')⊢4
@Adám
4
3
@JeffZeitlin Yes.
You can also use it to perform an action conditionally:
⋄ {⎕←'yup1'}⍣('b'='b')⊢4
⋄ {⎕←'yup2'}⍣('a'='b')⊢4
⋄ 'done'
@Adám
yup1
4
done
However, ⍣k can be quite limited. E.g. it doesn't give you the intermediary results.
@all Any ideas how we could get the intermediary results?
Jan 30, 2020 14:46
@Adám Operate on each of ⍳k?
@JamesHeslip Sure, but that'd be very expensive, as you'd end up running the function +/⍳k times instead of k times.
I want to say that the Scan operator is involved, but I'm not seeing exactly how.
It also wouldn't work well if the function had side effects or consumes external data.
@JeffZeitlin That'd be much of the same problem, as it also applies its operand +/⍳k times.
{⎕←⍵ ⋄ ⊂⍵}⍣3⊢'Yes' ?
@JamesHeslip That outputs the values. We want to catch them.
Btw, if you put your APL snippets in backticks ("`") it'll look better, and there's no risk of markdown swallowing special characters.
@all Any other ideas?
Jan 30, 2020 14:52
I thought maybe ¨ was involved, but that would seem to get back to the apply-+/⍳k-times problem.
Right.
How about an array to accumulate values?
Is it a trick question...? :)
No.
⎕←2{list,←⍺×⍵}⍣5⊢list←10 ⋄ list
@Adám
320
10 20 40 80 160 320
I tried something similar but with recursion. Not sure why I thought I needed it...
Jan 30, 2020 14:54
@all Does anyone see a problem with this approach?
You need to define a starting value for ⍺?
@JamesHeslip No:
@JamesHeslip - No, that's the left operand to the dfn that's the left whachamacallit to the ⍣
⎕←{list,←⊂⍵}⍣3⊢list←⊂'Yes' ⋄ list
Ah, I'm silly, forgive me
Jan 30, 2020 14:57
@Adám
┌─────────┐
│┌───────┐│
││┌─────┐││
│││┌───┐│││
││││Yes││││
│││└───┘│││
││└─────┘││
│└───────┘│
└─────────┘
┌───┬─────┬───────┬─────────┐
│Yes│┌───┐│┌─────┐│┌───────┐│
│   ││Yes│││┌───┐│││┌─────┐││
│   │└───┘│││Yes│││││┌───┐│││
│   │     ││└───┘│││││Yes││││
│   │     │└─────┘│││└───┘│││
│   │     │       ││└─────┘││
│   │     │       │└───────┘│
└───┴─────┴───────┴─────────┘
So, a problem here is that the argument and all results must be scalar. Observe:
⎕←2{list,←⍺×⍵}⍣5⊢list←10 11 ⋄ list
@Adám
320 352
10 11 20 22 40 44 80 88 160 176 320 352
IOW, using the prototype ⍺ ⍺⍺⍣⍵⍵ ⍵, you have 2 as ⍺, {list,←⍺×⍵} as ⍺⍺, 5 as ⍵⍵, and list (and its value) as ⍵
@JeffZeitlin Yes. and are arguments of the derived function. ⍺⍺ and ⍵⍵ are operands of the operator.
We should have gotten a nested array of pairs.
@all Any ideas on how to fix this?
⎕←2{list,←⊂⍺×⍵}⍣5⊢list←10 11 ⋄ list
Jan 30, 2020 15:00
@JamesHeslip
┌───────────────┐
│┌─────────────┐│
││┌───────────┐││
│││┌─────────┐│││
││││┌───────┐││││
│││││320 352│││││
││││└───────┘││││
│││└─────────┘│││
││└───────────┘││
│└─────────────┘│
└───────────────┘
┌──┬──┬─────┬───────┬─────────┬─────────────┬───────────────┐
│10│11│20 22│┌─────┐│┌───────┐│┌───────────┐│┌─────────────┐│
│  │  │     ││40 44│││┌─────┐│││┌─────────┐│││┌───────────┐││
│  │  │     │└─────┘│││80 88│││││┌───────┐│││││┌─────────┐│││
│  │  │     │       ││└─────┘│││││160 176│││││││┌───────┐││││
@JamesHeslip Almost, but you don't want the operand to return the nested result.
⎕←2{list,←⍺×⍵}⍣5⊢list←⊂10 11 ⋄ list
@JamesHeslip
┌───────┐
│320 352│
└───────┘
┌─────┬─────┬─────┬─────┬───────┬───────┐
│10 11│20 22│40 44│80 88│160 176│320 352│
└─────┴─────┴─────┴─────┴───────┴───────┘
Ninja'd!
@JamesHeslip Nope. That's not the same computation.
Jan 30, 2020 15:04
Ok, I'm not certain I follow then.
⎕←2{list,←⍺×⍵}⍣5⊢list←⊂10 11 ⋄ ⊂list
@JamesHeslip
┌───────┐
│320 352│
└───────┘
┌─────────────────────────────────────────┐
│┌─────┬─────┬─────┬─────┬───────┬───────┐│
││10 11│20 22│40 44│80 88│160 176│320 352││
│└─────┴─────┴─────┴─────┴───────┴───────┘│
└─────────────────────────────────────────┘
This looks like a nested array of pairs to me.
@JamesHeslip Sure, but here you're using a scalar function, but remember that × could be anything. You're passing it an enclosed vector instead of a vector.
⎕←2{list,←⊂⍺×⍵}⍣5⊢list←10 11 ⋄ list
@SamGutsell
┌───────────────┐
│┌─────────────┐│
││┌───────────┐││
│││┌─────────┐│││
││││┌───────┐││││
│││││320 352│││││
││││└───────┘││││
│││└─────────┘│││
││└───────────┘││
│└─────────────┘│
└───────────────┘
┌──┬──┬─────┬───────┬─────────┬─────────────┬───────────────┐
│10│11│20 22│┌─────┐│┌───────┐│┌───────────┐│┌─────────────┐│
│  │  │     ││40 44│││┌─────┐│││┌─────────┐│││┌───────────┐││
│  │  │     │└─────┘│││80 88│││││┌───────┐│││││┌─────────┐│││
│  │  │     │       ││└─────┘│││││160 176│││││││┌───────┐││││
Jan 30, 2020 15:07
You can either disclose it after the concatenation {⊃list,←⊂⍺×⍵} or use a "concatenate-the-enclosed" function for the modified assignment:
Sorry, mine was just a repost of @JamesHeslip
⎕←2{list⍪←⍺×⍵}⍣5⊢list←10 11 ⋄ list
@JeffZeitlin
320 352
10 11 20 22 40 44 80 88 160 176 320 352
⎕←2{list,∘⊂←⍺×⍵}⍣5⊃list←⊂10 11 ⋄ list
@Adám
320 352
┌─────┬─────┬─────┬─────┬───────┬───────┐
│10 11│20 22│40 44│80 88│160 176│320 352│
└─────┴─────┴─────┴─────┴───────┴───────┘
Jan 30, 2020 15:08
@JeffZeitlin That's a good idea too; increase the rank:
Doesn't look like it worked, though?
@JeffZeitlin Right, because is like , for vectors.
⋄ list←0 2⍴0 ⋄ ⎕←2{list⍪←⍺×⍵}⍣5⊢10 11 ⋄ list
@Adám
320 352
 20  22
 40  44
 80  88
160 176
320 352
This is a very efficient storage form, but only applicable if all intermediary results are conforming in shape.
OK, now we can write an operator that works like but returns all the intermediaries.
⋄ Pow←{⍺←⊢ ⋄ r⊣⍺ ⍺⍺{r,∘⊂←⍺ ⍺⍺ ⍵}⍣⍵⍵⊃r←⊂⍵}
⋄ 2×Pow 5⊢10 11
@Adám
┌─────┬─────┬─────┬─────┬───────┬───────┐
│10 11│20 22│40 44│80 88│160 176│320 352│
└─────┴─────┴─────┴─────┴───────┴───────┘
Jan 30, 2020 15:13
I know that's a mouthful, but I'll explain it all.
@all Did everyone understand the enclosing I did before?
getting there
I think so
So, I'm talking about 2{list,∘⊂←⍺×⍵}⍣5⊃list←⊂10 11 ⋄ list
First we add the original input as a scalar: list←⊂10 11
You assigned the enclosed vector to the variable, and then operated on the disclosed value of the variable?
Yes, because we enclosed it, the pass-through value is enclosed.
Jan 30, 2020 15:15
I've got it now
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 .
That's why we don't need to disclose.
We could of course have written ⊃list,←⊂ too.
So, the operator we're writing…
The first thing is ⍺←⊢. Is everyone familiar with this notation?
I'm not
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'
@Adám
hello
┌─────┬─────┐
│hello│world│
└─────┴─────┘
┌──┬─────┐
│hi│world│
└──┴─────┘
So, implicitly, it means to use the right argument as the (omitted) left argument as well?
Jan 30, 2020 15:21
So notice that the side effect of printing 'hello' only happened in the monadic case.
@JeffZeitlin No, ⍺←⊢ literally assigns the function to .
So, while normally and are arrays, can be a function in this special case.
That's my historical-APL showing; the early APLs I played with didn't allow that. Or at least didn't document allowing it.
Right.
⋄ {⍺←! ⋄ ⍺+⍵}4   ⍝ works with any function!
⋄ 2{⍺←! ⋄ ⍺+⍵}4
@Adám
24
Jan 30, 2020 15:24
Huh. Oh.
⎕←{⍺←⊢ ⋄ ⍺,⍵}12
@SamThompson
12
⎕←2{⍺←! ⋄ ⍺+⍵}4
@Adám
6
So this is a convenient way to write ambivalent functions.
@SamThompson This is a neat function. You could call it "vector", as it always returns a vector (for scalar and vector arguments).
So, 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 ⍺⍺ of the outer operator on its left, to pass in the function:
Pow←{⍺←⊢ ⋄ r⊣⍺ ⍺⍺{r,∘⊂←⍺ ⍺⍺ ⍵}⍣⍵⍵⊃r←⊂⍵}
@all Does this make sense now?
Jan 30, 2020 15:29
So ⍺⍺ is the left operand to Pow?
Yes, that's the syntax.
And we're passing it as the left operand to the anonymous operator {r,∘⊂←⍺ ⍺⍺ ⍵}?
Exactly. We could also have named it, and used the name.
⋄ Pow2←{⍺←⊢ ⋄ f←⍺⍺ ⋄ r⊣⍺ {r,∘⊂←⍺ f ⍵}⍣⍵⍵⊃r←⊂⍵}
⋄ 2×Pow2 5⊢10 11
@Adám
┌─────┬─────┬─────┬─────┬───────┬───────┐
│10 11│20 22│40 44│80 88│160 176│320 352│
└─────┴─────┴─────┴─────┴───────┴───────┘
/me nods
Jan 30, 2020 15:34
So, @Jeff, you got an answer also on how to write operators?
OK, let's step back a little. So far, we've seen using an integer as ⍵⍵. What does using a function as ⍵⍵ mean?
(Yes, I think I see what's happening with writing my own operator)
@JeffZeitlin ⍺⍺ and ⍵⍵ can be functions or operators. Just use them appropriately.
You can check what type of operand has been given you with ⎕NC'⍺⍺'.
@Adám in Pow2 why do you remove the ⍺⍺ from the left side of the inner dfn?
@SamThompson - he gave ⍺⍺ a name, f, earlier on
wait nvm i see
Jan 30, 2020 15:38
@SamThompson Because now the inner dfn lives in a scope where f exists, so f is relatively global to it.
before you are effectively referencing the reference
You could still pass it in to avoid using semi-globals (some people dislike such), but then you might as well just use ⍺⍺.
I'm looking at the example of ⍣ that calculates the Golden Mean (1 +∘÷⍣= 1), and I'm not seeing how that works.
@JeffZeitlin Right. I suggest planning that in the next Cultivation, we'll deal with with a function right operand.
OK, that'd be 13 Feb?
Jan 30, 2020 15:43
Yes, that sounds right.
A couple of things worth mentioning about ⍣k
The inverse ⍣¯1 is quite nifty, and can make things easy that are otherwise complicated.
Maybe the most famous 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. E.g.:
⎕←2 2 2 2 2 2⊤10 ⍝ 10 in 6-bit binary
@Adám
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
@Adám 10
So the inverse of also reuses a single base for "all" digits (that is, as many as needed):
⍞←2⊥⍣¯1⊢10
@Adám 1 0 1 0
Jan 30, 2020 15:49
can also invert non-trivial functions.
⋄f←32+1.8∘×
⋄f 20
⋄f⍣¯1⊢ 68
@SamThompson
68
20
Exactly.
It will even use a numeric solver if necessary.
There's an implicit assumption that f is a function that has a calculable inverse.
@JeffZeitlin Yes, it will DOMAIN error if it can't figure it out.
It also works with non-numeric things:
⍞←'a',⍣¯2⊢'aaaaa'
Jan 30, 2020 15:53
@Adám 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…
⎕←'a',⍣¯2⊢'abaaa'
@Adám
DOMAIN ERROR
      ⎕←'a',⍣¯2⊢'abaaa'
           ∧
Finally, I'd like to introduce you to 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.
E.g. We perform surgery under anaesthesia, and drive under the influence (don't!).
can make this very readable but 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
@Adám
12
If you know the @ operator, it can be used in combination:
⎕←'_'@2⊢'hello' ⍝ put an underscore *at* position 2
Jan 30, 2020 16:01
@Adám
h_llo
⋄ Under←{⍵⍵⍣¯1 ⍺⍺ ⍵⍵ ⍵}
⋄ '_'@2Under⌽'hello' ⍝ put an underscore *at* position 2 while reversed, that is, 2nd last
@Adám
hel_o
And that concludes today's APL cultivation. Thank you for joining and see you in two weeks (unless something comes up and I have to postpone it).
 
Conversation ended Jan 30, 2020 at 16:02.