@dzaima To be fair, ,kind of does that (output rank > input ranks) for scalars - 1,1 but i consider that an anomaly and a couple times considered removing it from my impl
The one thing left is just the 'how'... Of the three solutions so far for row-wise addition to a matrix, I still think yours is the most elegant. That is, your 'blank_starter←0 n⍴⍬' over my blank_starter←⍬ and then appending to a vector + post-processing with 'm n ⍴ vector'. And also moreso than the ⍪ ⍪[0.5] ⍪ ⍪ ⍪ ⍪ ... inconsistent mess of mine.
However, I'm creating the matrix (from scratch) in a recursive function. So by the time you're in it, the blank-starter should be made. However, ideally, nothing outside should concern itself with the shape of the array being produced within the recursive function. Which is why, although generally elegant, the ⍴ 0 n solution is still not ideal.
It requires whatever came before to know something about the shape of the matrix that the recursive function is about to create... Wondering if there's any way to not need to leak out the information about the matrix anywhere except where it's created
In other words, starter←0 n⍴⍬ ends up not being much better, in this particular usage case, than m n ⍴ result. It just means pre-processing rather than post-processing...
@dzaima Sorry? Am confused...
@dzaima Hmmm, super interesting! Didn't realize that. Writing an implementation really forces you to learn the language inside & out!
@AviF.S. i guess as the alternative m n⍴res also handles the case when you end up with 0 rows added ((r1⍪[0.5]r2) ⍪ r3 can't), so it doesn't really matter
And I'm still far more inclined to use yours over mine. Would just be nice if there was some way of not needing information outside of the recursive creator!
Does that count as encapsulation? Can I call it that?
@dzaima Makes sense! Definitely on my impossibly long, imaginary bucket list. Hopefully one day!
Also general chat-room question: When one has a general question about something, addressed to no-one in particular, at some point when no one is active: Is it reasonable to an @all/@everyone type thing? And is there even such a feature on SE?
Also, people have a magical way of appearing out of nowhere whenever someone says something. Just Murphy's Law, or are you guys somehow getting notifications even when not pinged?
@AviF.S. i'd just post the message without addressing anyone. the descriptions of CMQ and CMP are in the parenthesis.. (you can search for them to see what they're used for)
@dzaima Alright! And I did see the parentheticals, lol. Just still didn't know what they meant or how to create them in SE. Google is a good idea though!
@AviF.S. i wouldn't want that personally. Chromium (or maybe i was using vivaldi back then? idk) used to show a circle whenever there was any new message (especially useful pinned tabs, which these chat rooms are for me) but that doesn't happen now. Maybe worth making a userscript for that?
@dzaima No no, probably don't want it either, you're right. Just intrigued by how spot on people are about answering even when the room is empty. Also happened with @dzaima yesterday. And am sure Adám's also super speed. I suppose they all just do the same, then
I know that FireFox shows a count of "unread" messages in parens in the tab, and if there are any pings to you, it shows a * - so if there are e.g., 3 messages that I "haven't seen" any of them are prefixed @JeffZeitlin, I'll see (3*) The APL Orchard in the tab
@dzaima yeah, seems it's a Vivaldi feature to show a new message count bubble on tabs with unread messages
@JeffZeitlin that is an SE feature afaik so it should happen everywhere, but it's not that useful when the tab is pinned in chromium, which hides the title
@dzaima Super neat, always wondered why that wasn't a feature in Dyalog!! At least it's elsewhere :)
But again, post/pre-processing is not what I'm hoping for. Would be nice if the array info was self-contained!
@dzaima I'm saying I'd rather not do start←⍬ ⋄ m n ⍴ {…∇…} nor start←0 n⍴⍬ ⋄ {…∇…} nor even start←⍬ ⋄ 0 n ⍴ {…∇…} if it were possible. Nothing about the info re: matrix should leak outside {…∇…}. Should be the best of both worlds: start←⍬ ⋄ {…∇…} with some way to create the matrix within the recursive {…∇…}, from nothing.
@AviF.S. I haven't followed this conversation 100% but there is something I really don't understand
if you want to create a matrix with a varying number of rows, there is something we have to agree on: regardless of the number of rows you end up with, they always have the same number of columns, correct...? that is why it is a matrix
so there is something that allows to determine, in some intermediate recursive call, the number of columns of the row that you want to add at this intermediate recursive call...
so it seems reasonable that in the base case you can still understand how many columns you should have in your 0-row matrix, so that you can create an "empty" matrix with 0 n⍴0
@AviF.S. ah, you mutate start. My reasoning for why some _ n⍴ should be somewhere is that there's no explicit thing showing that at the end you'd have ≥1 row, so the code must give a sensible result for 0 rows too (namely, the correct column count), and APL makes you enforce that, which is good
It is like dzaima said, you can't make a recursive function without a base case and the base case must really be the simplest, most basic, most fundamental solution to the simplest version possible of the problem your function solves
@RGS You're absolutely right! How silly! Let me just replicate my workspace from before, should've saved it... And then test it out and confirm. But that all makes perfect sense!
@RGS @dzaima Thanks a bunch guys for all your help!! Super duper helpful and it will definitely work! Just nice to see it in action so will tell you when that happens!
Ah, all right! Helper functions are back up and running! It's a mess, though! I'm thinking about how to reformat the function so that your suggestion works...
Right now it's:
{... EndIf: Base mat⍪←...}
So it's not actually appending to the base case, if you see what I mean. The base case just tells it when to terminate the procedure of adding to something outside itself.
Will work on reformatting, but that's probably why it didn't suggest itself earlier. It's not natural given the way the function is formed. Working...
I don't think it's possible... Back to square 1? I left out some detail, it's of the form:
It's a gross oversimplification (the length of each row does remain constant in actuality), but there's two recursive calls despite only adding one line to the matrix.
So I can't change it to something of the form: {... base: 0 n ⍴ ⍬ next ← ... ∇ next ⍪← ...
}
Which was my original thought (since there's more than one additional recursive call per call). I don't know how else to say that ⍤. (Though, as far as I understand the term, head/tail means it's still primitive recursive since bounded, right?)
@all Oh well. Just making a helper function! Does anyone know how to have a function call another function whilst letting it access its variables? Global variables are a reasonable second choice, but having a little more control over scope would be nice!
Sorry, misread your response so the context seemed weird!
As for the second part: 'Defining the function in a scope with the variables is the only option afaik'
You mean that the variables have to be defined in the same defn?
I'm asking b/c in order to fix my recursive bit without making the whole thing a mess, it'd be nice if it could access information from outside which will remain constant throughout its execution. Otherwise, I'll have to make a helper pass it an '⍺' with the constant info, and then every recursive call will have to pass along the '⍺' as well. And I'll have to parse & rename the info encoded within the '⍺' every time. Which seems needlessly obfuscated!
it's the same behavior you've been using everywhere (how else could your dfns access mat from outside?), just naming the function instead of calling immediately
@dzaima well it is sort of possible, but it doesn't i definitely wouldn't suggest using that
@dzaima Wow, haha! Agreed. Will stick with the other for now ⍤
What I have now, thanks to you and RGS, is really elegant; there's just one tiny problem which hopefully won't require obfuscating everything:
I have: function ← { __len ← ... __mat ← 0 len ⍴ ⍬ __recurse ← { ____... __} __recurse ⍵ }
Spaces aren't rendering in SE chat for some reason, so I used '__' for indent instead...
Anyway, the inside recurse can access the outside function's variables perfectly, but it can't modify them. So it ends up doing nothing and mat remains ⍬
(also to note is that dfns will return on the first non-assignment line, so {… ⋄ recurse ⍵ ⋄ mat} won't return mat but the result of recurse ⍵ and never execute anything further)
My goodness! That's super elegant! Thanks a million :) That's exactly why I posted the format, to ask if there was a cleaner way to end it!
One last stylistic question is whether it's cleaner to never name the inner function at all. The outer one has a descriptive name which describes what the whole thing does anyway...
function ← {
len ← ...
mat ← 0 len ⍴ ⍬
{
...
} ⍵
mat
}
Somehow, I'm not liking that anywhere near as much... Thoughts?
@AviF.S. i don't necessarily like using multiline dfns inline, but it's rare i see any advantage of naming them either. Of course, personal preference, and very much can depend on the situation.
The inner function's not exactly long, but its 7 lines. I generally agree with you that it seems unnecessary to always name, but here it looks really weird to have a hanging ⍵ after 7 lines of code. And one wonders what the inside is doing; even though 'recurse' isn't that helpful anyway, I find it preferable in this case!
@dzaima 'Course! Makes perfect sense :)
Thanks again a million for all your help. Recursive functions which need access to constant info from outside come up all the time in my coding across languages. Maybe I just misuse/abuse recursion. (I often want to know attributes of the original argument, despite the recursive function having mutilated it.)
Anyway, so I'm super happy with this pattern and I'm positive it'll come up again and again. So all this help will pay serious dividends. Definitely, not a one time case. At least not the way I tend to code...
@AviF.S. reading variables from outside is fine imo, but mutating it is a bit strange, though often it's not avoidable without making everything more horrible (i'll always try to though)
@dzaima 'Xactly; good point! Well thanks again a bunch, serious lifesaver not just for functionality, but also made for seriously beautiful & readable code!
@all How to insert an arbitrary number of elems in a vector? Not so hard to write my own function but shocked that there shouldn't be a primitive/train to do so. @ is very picky about not changing the length of the original vector, for some reason...
As an aside: Does anyone know why @ doesn't like to change the length?
Was unable to find anything of reasonable length under !aplcart insert and related. There were some monstrosities at the bottom, though, but I didn't check them b/c I'd rather write it than copy it, if it's that bad!
@AviF.S. - For it to be a primitive, I think it would have to be triadic, somehow, and that's not APLish. I'm not sure I see how I would do this as a function unless there's some way to write a function that has multiple returns.
@AviF.S. - I don't think so - but I think you can do ((⊂'***')@4) '123-5'. That doesn't get you what you want, though; I'm assuming you don't want to change the depth.
@Adám Also, I must admit I find it amusing that it's 11:30 PM in the UK, yet you're here presumably because three days off for Shavuot/Shabbos has left you starved!!... or guilty?
(that's the problem with any insert primitive - there are multiple ways one might want to insert - positions in input or result, an "amount" array (with length equal to input's length), multiple elements at each or just a single one, etc; anyways gtg)
@dzaima That is a good point... but aren't there multiple possibilities for the implementation of most anything, hence design differences between the APL dialects, including yours? One simply has to decide how it'll behave, and something sure seems better than nothing!
@Adám Thanks a bunch, far cleaner than mine!! (I so far just had something primitive like 4{(1↑⍺↑⍵),'|||',⍺↓⍵}'123-45')
@Adám Ah, and thanks a mill for the explanation, as well! Always super helpful!
Probably would be nice if they were easier to find on APLcart, though you've so many goodies, it's inevitable that some things will be harder!
As I see it, the main conceptual problem with arbitrary possibly-length-changing "insert" and/or "replace" functions is that they are, necessarily, triadic - and there's no good way in APL to express triadic functions.
Well, I like to think that I'm a programmer, and I also like to think I'm functional, but I'm not sure that taking the two together makes me a functional programmer :)
@JeffZeitlin 'Course! I was just expecting what I sent after your response. Agreed that flattening takes another one!
Uh oh, wow... 90% of this page is taken up by green/aka me ⍤ ⍥ ⍤
@Adám Whoops! Missed your response. I see! Any sense of which it would most likely be? And if it's a likely addition eventually? Aka, how often does it come up/bother you in your workflow?
@all What fraction of the time that you use @ do you use it to change individual elements/wish it could do more?
@AviF.S. Almost never. I suspect that if you're inserting, then you're not taking a good array approach, and/or you're dealing with a tricky problem that doesn't lend itself to that.