Conversation started Feb 13, 2020 at 14:30.
Feb 13, 2020 14:30
Welcome to APL Cultivation!
This week's topic builds on last week's where we went into depth with the Power operator using an array right operand.
If you didn't follow that lesson, please check it out now.
with a function right operand is conceptually simple, but has some gotchas to be aware of.
For this lesson, 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.
@all Anyone following?
I think so.
E.g. 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.
@all Exercise: try writing an APL statement to the bot that computes ((10÷2)÷2)÷2… until it stabilises.
@all Need hints?
Feb 13, 2020 14:45
Ummm... That's not going to stabilize unless it takes 0 as being "0 within the comparison tolerance"
Floating point precision will eventually hit the point where half of the current number is "0".
OK. I'm seeing 10÷⍣⍺⍺2 but I'm not sure what ⍺⍺ should be.
@JeffZeitlin So your code has two issues. There's your lack of ⍺⍺, but also remember that the left argument stays constant, and the right argument is updated.
Ummm...
OK, now I'm seeing 2÷⍨⍣⍺⍺10, but I'm still missing what ⍺⍺ should be...
10÷⍣⍺⍺2 would do 10÷2 and if (10÷2) ⍺⍺ 2 then it'd stop, otherwise it'd do 10÷(10÷2) etc.
@JeffZeitlin ⍺⍺ gets called with the newest value on the left and the previous on the right. You want to stop if they are equal to each other.
Read as "until" or "until two subsequent values are"
Feb 13, 2020 14:53
That implies a simple =, then -
2÷⍨⍣=10
⍞←2÷⍨⍣=10
@Adám 0
Yes. Indeed. Nice.
The power (no pun) of is of course that you can use any functions as operands.
(a good example of something that APL detractors will say 'looks like line noise'...:))
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.
@all Task: 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.
Any takers? You'll need a user defined function (you probably want to go with a dfn or a train) as g.
Feb 13, 2020 15:05
OK, so we're looking at (2×⍣⍺⍺1) > 100, but I think ⍺⍺ may need to be something like {100<}
@JeffZeitlin Yes exactly. You just need the correct argument on the right of <
Oh, that looks like a standard dfn, then, so (2×⍣{100<⍺}1) - we use ⍺ instead of ⍵ because - like you said - if we use the right argument, we'll go once too often.
⍞←2×⍣{100<⍺}1
@Adám 128
Bingo!
Feb 13, 2020 15:10
Is ⍺ the result of 2×⍣?
@all OK, let's do one more to hammer it in. Given a string, keep dropping characters from the from until it is a palindrome.
(I should confess here that I have a copy of Dyalog running locally to check.)
@TomCockram It starts off as the result of 2×1 then it is 2×2 etc.
@JeffZeitlin That's fine. And for those without local APL access, there's tryapl.org
Damn, I've was using power the whole time
@SamThompson What do you mean?
Feb 13, 2020 15:12
as in Dyadic star
instead of multiplication
Oh :-)
For this latest challenge, we need to test first, I think.
BRB
@JeffZeitlin Good point. I wanted to make you all aware of that: will always apply f at least once. Beware!
So here's one solution:
0
Q: API for network

Nafiseh DaneshianI have to write a program with c# to find the printers which have same logos over netbios protocol The printers are in different subnets and they are netbios enabled They have been connected with each other by workgroup network Is there any special API for this aim?

⋄ IsPal←⊢≡⌽ ⋄ Palify←{1↓⍣{P⍺}⍣(~P⍵)⊢⍵} ⋄ Palify¨'otto' 'risotto'
Feb 13, 2020 15:17
@Adám
VALUE ERROR
      [] Palify←{1↓⍣{P ⍺}⍣(~P ⍵)⊢⍵}
                            ∧
⋄ IsPal←⊢≡⌽ ⋄ Palify←{1↓⍣{IsPal ⍺}⍣(~IsPal ⍵)⊢⍵} ⋄ Palify¨'otto' 'risotto'
@Adám
┌────┬────┐
│otto│otto│
└────┴────┘
So 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.
@all Is that clear?
And IsPal is a train that compares its right operand to its own reflection ⌽
@JeffZeitlin Its right argument, yes.
Feb 13, 2020 15:22
Yes, sloppy terminology on my part.
Sometimes, all your code can reside in g.
In which case f would become ∘ ? i.e., ∘⍣_g_?
@JeffZeitlin No, you still need a proper function f, but it can be trivial.
Not serious, but here is an example where f just increments until a complicated multi-statement condition is fulfilled:
⍞←1+⍣{a b c←⍎¨⍕⍺ ⋄ (c=a+2×b)∧3=⍴∪a b c}400
@Adám 416
(note to self: FIREFOX, not Chrome, dammit!)
Feb 13, 2020 15:27
@JeffZeitlin Better?
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.
E.g. here is an expression to collect lines of text from the user until they enter a blank line:
¯1↓text⊣{text,∘⊂←⍞}⍣{''≡⍺}text←0⍴⊂''
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}⍬
@Adám
4
4
2
Since it is random, let's try that again:
⋄ {}{⎕←?10}⍣{6=?6}⍬
@Adám
3
1
5
4
10
4
1
7
6
6
OK, why did it output the sixes that time?
And why two of them?
@JeffZeitlin It doesn't output the condition roll, just some random number each time.
Feb 13, 2020 15:36
@Adám if a challenge already has a submission in APL+WIN is it eligible for the bounty?
Did not see it in the list for the bounty post
Ah. So it's actually rolling a D10 followed by a D6, and the D6 controls whether it rolls the D10 again.
@JPeroutek No, sorry. As it states: The challenge had no previous answer in any of the above languages.
@JPeroutek "APL+WIN" is a subset of "APL+", no?
@Adám I'm not entirely sure lol. I'm new to it, just started messing with it a week ago
@JeffZeitlin Yes, here is one that keeps rolling until it gets a 6:
⋄ {}{⎕←?10}⍣{6=⍺}⍬
@Adám
4
9
6
Feb 13, 2020 15:38
/me nods
@JPeroutek Where did you get hold of APL+WIN? afaik, it is only available at quite a high cost.
And APL*PLUS from the DOS days should also be covered by APL+, as that was its original name...
I didn't get a copy of it, A question I was looking to answer had a submission in apl+win
@JPeroutek Ah yes, sorry. I misread there. Of course, you're free to answer in another APL. I often outgolf existing APL+WIN solutions. And you can still get upvotes, just not that bounty.
I have a DOSBox with ... four APLs on it.
Plus a Dyalog installation, plus a NARS2000 installation.
Feb 13, 2020 15:41
I see, Ill give it a shot. For reference, this is the question I was looking to answer
12
A: How lit is this room? 🔥 pt. 1

JPeroutekPython 3, 388 398 408 409 415 417 493 bytes To make it more accurate, increase n from random import* u=uniform c=lambda A,B,C:(C[1]-A[1])*(B[0]-A[0])>(B[1]-A[1])*(C[0]-A[0]) I=lambda A,B,C,D:c(A,C,D)!=c(B,C,D)and c(A,B,C)!=c(A,B,D) def a(l,v,n=9**6,s=0): g=lambda i:(min(x[i]for x in v),max...

I made the approximate python solution, but I was looking to make an exact APL solution
I likely still will
@all OK, so far so good. Any questions on ?
I'll show you a trick using f⍣g. Sometimes, we can have a nested list of lists of lists, e.g. 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. Any ideas?
Seems pretty clear to me. And makes ⍣ one of the more powerful constructs in APL
E.g. 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]]]'
@Adám
┌─────────────────────────────────┬────────────────────────────────┐
│┌──────────┬──────────┬─────────┐│┌────────┬───────────┬─────────┐│
││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, i.e. without querying the depth?
Feb 13, 2020 15:47
Ooof. That's a toughy; I think I'm seeing a fair amount of ,⊂ in there somewhere.
@JeffZeitlin No, it is just
⎕←((5 22 13 18) (9 19 16 11) (4 2 12 20)) ((8 6 17 1) (10 24 15 14) (21 23 7 3))
@Adám
┌─────────────────────────────────┬────────────────────────────────┐
│┌──────────┬──────────┬─────────┐│┌────────┬───────────┬─────────┐│
││5 22 13 18│9 19 16 11│4 2 12 20│││8 6 17 1│10 24 15 14│21 23 7 3││
│└──────────┴──────────┴─────────┘│└────────┴───────────┴─────────┘│
└─────────────────────────────────┴────────────────────────────────┘
Oh, wait. No, you want to UNENCLOSE.
Right, or "Mix"; monadic :
⎕←↑↑((5 22 13 18) (9 19 16 11) (4 2 12 20)) ((8 6 17 1) (10 24 15 14) (21 23 7 3))
@Adám
 5 22 13 18
 9 19 16 11
 4  2 12 20

 8  6 17  1
10 24 15 14
21 23  7  3
Feb 13, 2020 15:49
But how do we know how many time to apply ?
When the mixed result is the same as the previous result?
Exactly! Now write that!
⋄ ↑⍣{⍵≡⍺} ⎕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]]]'
@SamThompson
 5 22 13 18
 9 19 16 11
 4  2 12 20

 8  6 17  1
10 24 15 14
21 23  7  3
Feb 13, 2020 15:51
@SamThompson Good. Now golf that.
↑⍣≡⎕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]]]'
Yup.
Think I'm starting to get the hang of it
So ↑⍣≡ is a neat idiomatic expression. Remember it.
@all Challenge: 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?
So, for 2 3 4⍴⍳24 we want to get ((1 2 3 4) (5 6 7 8) (9 10 11 12)) ((13 14 15 16) (17 18 19 20) (21 22 23 24))
⋄ mat←2 3 4⍴⍳24 ⋄↓⍣{⍬≡⍴↓⍺}mat
Feb 13, 2020 15:58
@SamThompson
┌────────────────────────────┬─────────────────────────────────────┐
│┌───────┬───────┬──────────┐│┌───────────┬───────────┬───────────┐│
││1 2 3 4│5 6 7 8│9 10 11 12│││13 14 15 16│17 18 19 20│21 22 23 24││
│└───────┴───────┴──────────┘│└───────────┴───────────┴───────────┘│
└────────────────────────────┴─────────────────────────────────────┘
@SamThompson Nice, but it encloses a simple vector.
So we'd need to test whether ⍴⍴mat=1 before doing anything.
@JeffZeitlin Exactly, but 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
@Adám
┌────────────────────────────┬─────────────────────────────────────┐
│┌───────┬───────┬──────────┐│┌───────────┬───────────┬───────────┐│
││1 2 3 4│5 6 7 8│9 10 11 12│││13 14 15 16│17 18 19 20│21 22 23 24││
│└───────┴───────┴──────────┘│└───────────┴───────────┴───────────┘│
└────────────────────────────┴─────────────────────────────────────┘
This concludes today's lesson.
Feb 13, 2020 16:04
⋄mat← 2 3 4⍴⍳24 ⋄{1=⍴⍴⍵:⍵ ⋄ ↓⍵}⍣{⍬≡⍴↓⍵}mat
@SamThompson
┌────────────────────────────┬─────────────────────────────────────┐
│┌───────┬───────┬──────────┐│┌───────────┬───────────┬───────────┐│
││1 2 3 4│5 6 7 8│9 10 11 12│││13 14 15 16│17 18 19 20│21 22 23 24││
│└───────┴───────┴──────────┘│└───────────┴───────────┴───────────┘│
└────────────────────────────┴─────────────────────────────────────┘
⋄ {1=⍴⍴⍵:⍵ ⋄ ↓⍵}⍣{⍬≡⍴↓⍵} 1 2 3
OK, that works, too, and probably is the better way to handle it; I was thinking that we'd revisit the palindrome problem, and replace ↓ with a similar function to IsPal
Sam's solution is what I was thinking of!
(vs Adám's with the disclose)
 
Conversation ended Feb 13, 2020 at 16:08.