Conor

Welcome to Raycast, episode one hundred and twenty-nine. My name is Connor, host of Raycast, and today with us we have two panelists. The panel has grown, folks, by 50%. I guess we will go around and do brief introductions. We'll start with Adam and then we'll finish with Madeline.

SPEAKER_01

Right, so I'm Adam Butowski. I am the head of language design at Dialogue, and I've been doing APL for a long time. And over to you, Madeline.

SPEAKER_03

I'm Madeline Vagani. I am the creator of Tiny Apple. That's probably how you know me if you do. And yeah, I've been doing that for about four years now.

Conor

Awesome. We are happy to have you today. We mentioned, I think it was uh a couple months ago now. I think it was back in June, and technically we're beginning of August, that we were looking to grow the panel. And so we are in the phase where we are going to be bringing on guest panelists for the next little while. And we are very excited to have Madeline as our first guest panelist. And I guess I usually say uh as mentioned before, my name is Connor, host of Raycast, massive fan of all the array languages. And with that, uh let me know if my audio is too loud because uh every single time it's too quiet. But now I see the mic going super red. So uh I might have to adjust this. But while I do that, we will throw it over to Adam, who I believe has two announcements for our episode today.

SPEAKER_02

Yeah, so the first one is at the APL Forge, uh, which is this annual thing that dialogue has going where people can submit projects that they've been uh doing in dialogue APL or for dialogue APL, um has concluded a round. Next one has started. Um you can always submit ideas, look at forge.dialog.com. But the point is here that the winners for this year have been unannounced. Um so there is uh there's something that might be known on the podcast here, but uh Carl Krokin with his uh boxing game and our very own Connor Hextra with his array box. So that's uh one thing. Uh the other thing has a little bit to do with Madeline, or a lot to do with Madeline. Oh, yeah, congratulations, Connor. Look at that. Look at that. Um for the audio listeners, there are now uh celebratory things, uh icons floating up over the screen. Uh courtesy of Madeline.

Conor

Um it's courtesy of me. I'm doing it myself.

SPEAKER_02

I didn't know what to do.

Conor

I wasn't sure I was gonna be able to get this to work on uh uh Google Meet.

SPEAKER_02

Okay, my screen is showing up on Madeline's face. I don't know why. Um right. The other thing uh has something to do with Madeline, actually. So Madeline's been uh had uh she she got this uh grant from the APL Trust to uh work on the APL 387 fund, and I uh happened to notice that APL64, which is the new offering from the traditional vendor of APL Plus, um it now ships with the very latest version just came out. Uh it now ships with APL 387 bundles. Um so that's pretty cool that they've sort of picked that up uh without anybody from our side at least the time. Like to have them part of the community a little bit. Create just a corner. Um also ships to APL 387, the next next uh latest version, every new build probably built uh that is cool to see.

Conor

Interesting. So it is pervasively uh I try to think actually, too, on my site, the one that won for the contest plug. I don't even remember the shortcut, but I know control H is uh is for the help, and then yeah, you do use APL387 as well on the on for the font there.

SPEAKER_03

I think it changes within the languages.

Conor

Yeah, yeah. If you go control B, it shows the fonts per language. So 387 is used for APL cap in tiny Apple. Uh J uses JetBrain's mono, Wiiwa uses Wii Wa386, and BQN uses BQN386. So half of the languages on a ring.

SPEAKER_02

But it could be more. You could you could switch BQN to use APL387 as well. It's now it now has full coverage for BQN, I believe. And Wiiwa support is in progress, or at least scheduled, planned, uh to happen as well. So you could actually go universally AJ, of course, doesn't care because it's just ASCII, of course, it covers Hasky.

Conor

Right, right.

SPEAKER_02

We're aiming for APL387 to become the universal array or Iversonian array language fund so we can handle every Iversonian array language.

Conor

Awesome. Well, uh I'm not sure if there's a link for that, but if there is, Adam will send it to me after the show and I will put it in the YouTube description slash uh show notes on the website arraycast.com. And I think with uh those two announcements out of the way, we are going to I don't we didn't actually officially decide. Are we doing uh little problem solving today in multiple languages, or are we gonna pivot and then call an audible at the last second live on uh YouTube uh to a different topic? What say the panel?

SPEAKER_02

I mean we can I think we can start with uh little problem solving and see what it takes us with discussions and things.

Conor

Okay. We didn't discuss this either, folks. This is all happening live. Uh who's screen sharing? Is it gonna be Adam? Although, because Adam's got the laptop with the issues or the computer with the issues. Uh is it better if Madeline screen shares? What uh what should we do?

SPEAKER_03

Well let's let's look at the problem before we volunteer.

Conor

Well, uh we can't look if no one screen shares, but I mean technically I can uh drag it over our faces if we want, but I can uh read the problem, although now I don't actually know. It's on my left monitor. So we're gonna be looking at this week's challenge, which just dropped in the last 12 hours if you're listening to this live, and plus however many hours if you're not listening to it live, and we're gonna skip task one of challenge 385 from Pearl Weekly Challenge and go to task two, which is a twist on a classic APL problem. So I will I'll I'll hover it over my whole screen now. I'll hover it over my face, and you can see our two other uh beautiful panelists, but not me. And it's called outermost parentheses. Uh you're given a valid parentheses string and it's asked to write a script to return the string after removing the outermost parentheses of every primitive string in the primitive decomposition of the given string. So if you're an audio-on listener, you'll have to pay attention to what is a primitive decomposition. But if you're watching this on YouTube, you probably just by looking at the examples, have already uh deduced what a primitive decomposition is. But basically, it is for any valid substring of that string. Um, well, I guess it has to start left to right, so because you could technically take an inner uh parentheses if you're not starting from left to right. But if you start from left to right and each time you can take a substring from that point uh that is a standalone valid set of uh parentheses, then like that's your first component or chunk of your primitive decomposition. And then you just recursively do that. So for the first example, it's left paren, right paren, left paren, right paren, left paren, right paren. So that decomposes into just three sets of left and right parens. And so the result of that example is an empty string because if you just have three pairs and you remove the outer parens, you're left with nothing. Um and then I don't think we need to go into the other examples. Um, but if you're watching on YouTube, there's a couple other example two, three, and four.

SPEAKER_02

So that is the uh the the sentences are they only consist of parentheses, right?

Conor

Uh yes, it and it's it's guaranteed to be valid. You don't need to do a validity check up front.

SPEAKER_02

Um yeah, okay. So that it is actually an interesting problem because this this you can solve in in multiple ways that I can think of. Perfect. Immediately.

Conor

A little inside baseball, Adam said, huh, you know, it's not too interesting before, because uh everybody knows how to do this because it go it dates all the way back. Was it the um notation as a tool of thought? Does it come up in this paper, or it comes up in a paper that is like decades old um that Iverson shows the outer product solution? Um I can't remember which paper it is, maybe someone in the chat. Uh although now I've lost my uh access to the chat. But yes, this is what we will be solving.

SPEAKER_02

That's a classic, classic sort of problem, at least. But but there are there are some interesting approaches because we're not interested in the actual level of parentheses, we're only interested in what's re what remains when we remove all those parentheses. Um that means we can I can I'll start with a sort of a cheating uh uh uh solution. Let me let me share my screen.

Conor

Oh yeah, I just I just thought of a neat trick as well for solving it. Yeah. That avoids that avoids partitioning. Yeah. Well then I wonder if that actually works. That would be crazy if it works. I won't I don't want to spoil it for for the the listener right now, but I'm thinking of well so should we should should one of us um oh here we got the screen share, so we're getting rid of the problem description. Actually, here I'll link it. We never we never link these uh problem descriptions. It's linked in the uh YouTube um live comments, and now Adam is screen sharing. And uh let's uh should we do something the classic the classic well actually what is the classic or naive way you would solve this? I don't know, maybe there's not even agreement on that.

SPEAKER_02

No, I think the classic it's not naive, but like the classic thing is to look at the parenthesis level, right? And then so every time we have an open parenthesis, we can like increase the level that starts from zero by one, and every time we're closing parentheses, we can we decrease it by one. This gives us for every character the ones that are um that are um like the the level that they're at. Now I don't remember exactly how it was like there can be there can be other text, right? Because we want to return what's there, right? With this, we want uh this is yeah, sorry, I'm using an experimental interpreter that's going to give me errors all over the place. So um that's going to be fun. Uh one second. I'll I can do better. As you did mention that uh I'm the one that's using the laptop that has issues. And APLs that have issues. Sorry. I should be the reason. Uh let's close this one down if I can. Well it is crash if it can't close, or just I think it can close. Okay. Brand new one. Ladies and gentlemen, this is where you saw it first. This is dialogue version 22.

Conor

Were we on 21? You're telling me you're telling me the 22 is gonna have less issues than the 21?

SPEAKER_02

No, it's just that my installation was well using experimental 21 for something somebody was working on it's not an issue. Okay. Uh I just wanted to confirm something because you don't have the problem description of Randall. So this is this should return ABC, right? And even even this should return ABC, if I understand right. But it's easier to see what we're doing. Um and so we can we can uh we can see what the correspondence is between these numbers, and then we can uh do a subtraction vertically. So for each parenthesis that's opening, we're subtracting one minus zero or zero minus one, so it gives us positive negative numbers, so it gives us the change um for and in the parenthesis level, and if we then do a running sum, then we get the parenthesis level. Of course, it's it's slightly offset because we say that the opening paren is part of the new inner parenthesis, but the closing parent is not, but we can adjust um for that. And so we can see that when we have an opening paren that's a one, we remove it. We have a closing parent that's a zero that needs to be removed. So this is actually enough. We don't even have to uh to do any of the adjustments. So we could here say this is our this is uh the depth, and and then we can say and if t is equal to um an open parent, and the depth is equal to uh to one, or parentheses for that here, or if t is a closing parent, and uh the depth is a zero, so this is this is our depth, and this is these are the parentheses that we want to eliminate. That means if we negate this uh hitting our buttons, that gives us a mask for the original text. Okay, so if we stick that into the mouse, and then we can do the mask and replicate on the text, and that we've got what we want. So this is one way we could do it. We could also adjust directly these numbers by some rotations so that we get a and a zero in those those positions. We can try doing that. Um so if we go back for a moment, so let's uh start with this one again. We've got D here, which is which is the level. Um we can we also have our original masks over here. So really what we want is that if there is a uh a one in the bottom and there's a one in the depth, right, or there's a one on top, and that's the opening. Right, but this is this means open uh this means opening these two together, and this means closing, and this is the uh this is the depth. So here we've got uh open close, open close. So if you have a zero over here and we've got a one down here, or if you've got a one up here and a zero down here, right, and the level is one, then those are the ones we want to eliminate. So and so we can say if we we can we can match that, right? We if we want a function where only one zero on top to the bottom gives one, and only uh we want zero at the top and one at the bottom to give zero, and then we want to eliminate them. So we can do some some mathematics here. If you want exactly these this one pointed out, uh that's that's where we could just do the top row, it's actually easier. So we can just we have the depth. Sorry, I'm just sort of moving around here uh between them. Do the depth, that's this one. Um and we also have the top and the bottom rows from these two. So if we split up the comparison into these two, and we say this is opening and this is closing, you stack them on top of each other, that's the same same matrix. Now we have them as separate um separate vectors, and it makes it a little bit easier to deal with them in this case. Um then if we got opening and the depth equals um one, and that's the same thing as I did before, and then then we can say or we have closing and the depth equals zero or NOR, right? Because that's we want the one the mask. There we go. And then we can take T like that. It won't have the same length, but we can put this as a mask, and then we can say mask. This is a fairly fairly clean way of of writing it as three segments without having to do a like a new comparison of and we just do this as the minimum number of comparisons that we have.

SPEAKER_03

Well, surely you don't need to check for closing, so you know, just say negation of the other one. What do you mean through that to look for closing? Well, C is just not O.

SPEAKER_02

Yeah, that's true. Right. This this is a more general one, right? This will work even if you have additional text in there, it's like sort of inadvertently that. So yeah, you're right. We can we can combine them like this. Uh which means well, we could we could combine them like this, and which which is the same. Um and then we can we have a by the way, a uh uh comment in the chat uh that saying they didn't know you could evaluate inside uh array notation to this degree where you can set it inside and next cells can use their soul. So every every value expression inside array notation is just normal APL expressions. So whatever side effects happen there, they're they just happen, so you can use them later. However, we don't even need to assign O here because we can we can use C over here, and then we can just say because we know it's Boolean, instead of and we can just say that it's less than this less than is actually the same thing as not left and yes right. So we don't need to set that. Did I make a mistake? Uh oh, because the depth, I forgot to set the depth. That's right. So we do need both. I forgot to say that D gets plus backslash uh open minus close. So this only prints the openings, not the closings. And then uh we can get rid of that for now. The depth and mass and results we have over here. Can we combine this further? Can't really think of a good way to do it.

Conor

Well, what does this look tacitly? Because you got one, two, three assignments.

SPEAKER_02

Yeah, it's not going to be very nice tacitly. We c it can obviously be done, but we can try it, but it's not going to be beautiful. So so if you want to make it a function, yeah, first let's make make this a proper function. So we don't want to return these things, we just want to compute them. And okay, so this one is explicit and let's try to make this tested, but it's not as again, it's not going to be nice. So we'll start by this mask over here. We combine that, and every and then we also eventually we need um oh, we can actually do this as a giant behind because we're going to compute a hu a mask and then we're going to apply it to the original argument. So we're going to have some giant function over here, and it's going to be really nasty. Um, so let's space this out to help readability just a tiny little bit. And for this, we need uh we need to find the two um c and o. One of them is going to be uh the original, and the other one is going to be the not. And then we're going to subtract them from each other. That's over here to get the d, and then we do the um the running sum. So now we've we're up to d over here. The problem is that we don't just want d and continue computation, we also want back references to to O and C as for the formula over here. So we're going to glue these two together and have a function that's between these two, which by the way, this can also be a behind, but we can get back to that because we have a right tag here and a knot over here. Um but we'll get to that. Um okay, so this is D, and we now have uh this is there's going to be some repetition here, which is not going to be very nice. So we want where one equals taking the left part first, and O is on the left, that's the negated one. So we want the left argument and one equals D. That's so this is the the left side of the NOR over here. And the right side of the NOR is going to be exactly the same. We might be able to simplify this a little bit. Um we're just going to have zero here like that. So I think this is all we need. If I haven't made any mistakes, we can try it. It didn't even work properly because I made some mistake somewhere.

SPEAKER_03

I think I write that on the second.

SPEAKER_02

Oh, it's this one. Yeah, it should be right. There we go. Okay. But I mean, this you don't want to write this tacitly. And we're doing computation twice. So we could potentially avoid the computation but computing this twice by merging together these two somehow, but it's not going to be very nice. Uh we could eliminate this outer function here by nick by doing something like that would be nice either. I think we can read this. Nasty. Oh, that is nasty. We can move the negation in here on both of them. And that eliminates the outer thing here. What's the chance I'm going to get my parenthesis right at this point? Uh okay, don't need this anymore. We can just put it inside. Okay. And then we need to apply this both sides here. And the right argument is that one, and the negation is that one. This might work. Yeah, it still works. Oh, I guess I'm doing the symbolic like manipulation in my head at least of the APL code. But I wouldn't exactly call this nice. Condenses a bit. Can you read this gunner?

Conor

Well, the thing that I'm thinking in my head is like, does it because like I have a solution, but it's just the outer product, uh subtraction, column-wise scan, or column-wise reduce, plus scan, and then I just add the uh equals write parent to it.

SPEAKER_02

Yeah, you can do that as well. That's the that's the other part, another approach to that getting the and or go should be.

SPEAKER_03

Yeah, where either thing goes in here.

SPEAKER_02

You can do that as well. Because we know that it's well formed. So so let's let's let's let's try this.

Conor

And and for the listener, D is the result of the plus scan on either the solution that uh Adams built here where you're storing the opening and closing parens and just doing subtraction or the outer product column-wise subtraction.

SPEAKER_02

Yeah, that's um so if you so we have D already, the depth. And if you do a one uh actually it doesn't minus one, I think. Minus one rotate, not one rotate here. So it's a guy. I need to I need to stack T on top so I can we can even put D. How do you know what the next thing is going to be?

SPEAKER_03

If either is a zero, you have to remove it. So you just take the minimum or multiplication order of D and the rotate direction. Yeah, because uh you have zeros where it's closing, and if you shift them, it's gonna be in the next opening, which it definitely uses to be the next one.

SPEAKER_02

Oh, because oh, because of the constraints, right. Again, I'm thinking that what are the other characters, but it can't be. So you know that if we're hitting a zero, the next thing after the zero has to be a one. There are no other options. That's true. That's cute. So if there's an if there's a zero in one of these, which actually we can uh we can actually cheat a little bit because we can look at yeah, I mean there are different ways to do it. We can compare them with zero, right? But we could actually also just multiply them. I was thinking of sine of sign and take the sign of that, yeah. Um so if you need that's a mathematical approach, right? If the if you multiply them, then we get this, and then this then the sign is the mask, and then we can we can filter filter with that. So we do and this will turn out nicer in a little bit in tacit at least. So if we go so again, minus vertical reduction on open close. I mean, even though this outer product is actually not really good because we're doing more comp comparisons we really need to, but okay, fair enough. This is D. And then we can this we can write in a nice tacit fashion. So we can write negative one and then the argument times the rotation. You're missing the uh missing the plush, and then we can do the the sign there, so we can take this whole function, but of course it doesn't work well testing, totally test it. But if you do it at a D near, then we can write it like this. Just that's what I need. That's nice. I need to go like wait, because we This is only this will not work if there were other characters in there. It will only work.

Conor

I know, but why do you need the D I mean I I guess you need the D font because you need to it's because of these monetic functions that uh it would we can totally do it tacitly, but it's just going to be really, really ugly because we need to we need to apply this monetic function.

SPEAKER_02

So we need to parenthesize. We can't bind it with an attack when we don't have not uh nothing either from B to N and J. Cap. We have to parenthesize it. And they use a lot of mutability in my opinion when you do this. But yeah, this works. I actually I think there are uh what do you say?

Conor

Oh no, it is a couple characters shorter, I was gonna say uh than uh my previous solution. That's a neat trick, the rotate uh yeah. Seems like this would be uh ideal well, it's hard to tell without actually trying it, but in cap you'd have uh only two trains, so you don't need the parens, and then you also have an outer product glyph.

SPEAKER_02

Um wait, there's something else I want to try here. So we still have to go through the depth, but if we do the depth here, and we can put T on top, right? So it's more readable. So a one is what we want to get. I want to get rid of the ones that are one and open. No, I was thinking about that. We could look at the at the pattern that we've got. This is what we want to eliminate. Ah, okay. I think I have an idea. We can we can look for this pattern of zero, one. Those are the ones, the ones that are above a zero, one are the ones we want to eliminate. So so let's see, let's say we do it like this. I'm going to replace it with a notation inside a uh entire function so we can give a single parameter. Let's say we do a one rotate of this. Now it's the well, it doesn't really matter. Now it's the negative one zero. We can also rotate the other way around, and it's going to be the same negative one zero. And anywhere we have negative one zero, that's when that's what we want to eliminate. So if we look for this pattern, we can also do it after we do the uh do the running sound like this. So we can do one here, and now so what happened now when we rotated the first character uh to the end is that that uh we should do that one rotate here as well, otherwise it's hard to understand what's going on. So we take the first character move to the end, and that means that we're pairing that one the opening with a closing from here. So now what we want to eliminate are the characters that are above the zero one. So we've got one here, we've got one here, and we've got one one over here. Okay, so um if we we can start by doing it with fine because it's easy to spot what's going on. So this gives us a mask where we have we've got zero one. And we what we want is the next character after that as well. So we can do a a one rotate on that. Sorry, did I make a mistake here? Oh, yeah. That that points at the next character. Oh, minus one rotate, sorry. Minus one rotate points at the next character. So one of those two. So if we do if we do combine them again, so we can make this little train, this or the rotate, that those are the characters that we want to eliminate, which means the NOR on that is are the ones we want to keep. And it doesn't matter that we rotated the initial character to the end because the initial character will always be eliminated. There's no other way. So now we can do this whole thing like this, and we have to uh rotate well, it's rotated the step, so we have to rotate, we either rotate the mask or we can rotate the uh the input over here, so like that. Is it shorter? No. Sort of a different way of doing things. And this we can we can change this whole thing to use a pairwise um instead. So we can say we're looking for looking for looking for that, and then we we rotate it right and left, so we do want to put a zero in front or behind. So this is that alright, what I'm doing. Oh no, because these are actual numbers. Yeah, we can't do that. We have to look for the pattern of zero, one. It's not a boolean. But this works. Um I still think that's a better way to do this.

Conor

Well, I posted uh in the chat um uh the cap equivalent of the last solution, which uh is very nice. Here I'm I'm blocking your screen now. You have to go to the YouTube live stream to see this. Uh but uh it's just nice because like I said, it it has the outer product primitive and uh oh and the and the the array with primitive that binds together, yeah.

SPEAKER_02

Yeah, so but I'm not sure I mean what we're doing here is this thing in cap, I would guess you can write that differently. Let me try it. I have uh I have it over here. I'm not showing my my array box, I don't know exactly what's on the on the stream. So because of the way things bind, I would think that we can how is it in cap to write a scalar character, you write like an add sign in front? I think yes, yeah, yeah. So if we do add open paren equals no, we're not allowed to do that, right? I wanted to do something like this. But we but it's that's a fork.

SPEAKER_03

Oh, but you can just do uh like equal to the closing one and then you do like oh and the not, yeah. Yeah, not uh before subtract or something like that.

SPEAKER_02

Right. So if we do equal to view this, um and then we do the not subtracted from that. Does it work? Or it already evaluates, right?

Conor

Uh well no, if you hit enter, that gives the same result, so I guess. Yeah, yeah. I guess I should put some little confetti every single time you hit enter.

SPEAKER_02

I see is following what's happening here? So we're taking taking the closing paren and comparing with the whole string. Then we're taking the negation of that and subtracting the original value, that's what behind does, and then we do the the running sum. I think that's nicer than the outer products.

Conor

Uh it is, although I have to say the at is an ISOR. Um yeah.

SPEAKER_00

But other than the VGN's way of writing it like this.

Conor

I mean I do like the I do like the two characters. I just like the at is not very uh APL font-ish, you know. Or character, no, or symbolically, like it's using the right font, but it doesn't, it doesn't uh although you know you could argue that the a couple of these, like the the fork syntax and cap is a little um um yeah, something oh wait a minute.

SPEAKER_02

I think I think in BQN uh you don't need to do this at all because or or if if you've got if you one second. If you've got uh F and characters, these two are one off from each other, right? So you can actually just subtract adjacent characters just and go from there.

Conor

Unfortunately, you don't you don't have uh pairwise uh No, you can't have everything, right? Yes, you can. You just go straight to Tiny Apple.

SPEAKER_02

Well, Tiny Apple has has appeared characters as well? Yeah, of course.

Conor

Of course. Of course. And if it's if it's missing something, uh you just switch to it, you know.

SPEAKER_02

Okay, Matt Medelin, do you want to drive? You want to share your screen?

Conor

Um also Marvel Com Coma in the chat says uh they solved this earlier today. If you've got uh link and you want to drop it in the chat, uh we can show your Wiwa solutions um if you want. You know, it's kind of putting you on the spot, but uh okay.

SPEAKER_03

So we want this the parabolic subtraction. Okay.

SPEAKER_02

Uh yeah, so this is right. Uh you know that it's negative negative one of the ones uh in the area we want to to eliminate.

SPEAKER_03

Oh, because it's right, so we just do this. No, I don't think that's right.

SPEAKER_02

Yeah, because think about it, the ones we want to eliminate, except at the edges, right? We know that we want to drop. Oh yeah, we could have done that. We could have done like a one drop, negative one drop as well. Because you know the person that character must be removed. So the ones we want to draw to get rid of are the ones where you got one negative one, right? What is this?

Conor

This is it can be that that can exist though, nested in a primitive component, so I don't think that actually works, right? I'm pretty sure actually one of the examples.

SPEAKER_02

Oh yeah, it's no you have to go, yeah, you have to go to the scan, of course. Yeah, yeah. That's it doesn't help.

SPEAKER_03

Because we don't really care about the difference between like what do I find characters actually give you? Like compare. Yeah. If you do a scan on that. The second one is a sound scan. Yeah. Yeah.

SPEAKER_02

No, we still can't tell where what level it's at. There might be some way to do this using using the the differences, but well one thing you can certainly do instead of comparisons with the parentheses, you can just subtract 40, right? Or subtract the character before and what is 39? It's going to be all.

SPEAKER_03

Yeah, but I don't think it's that much better. It's probably clear to just write the comparison.

SPEAKER_02

No, it's not it's not even shorter. I'm sure there's some drag X way to do this with some balance and terrorist thing.

SPEAKER_03

Probably nothing. It seems like there should be a way to do it without the whole depth, but not true. Because it gives you a lot of information that you don't need.

SPEAKER_02

Yeah.

Conor

Should we look at Marblecoma solutions? Uh and then see if we're inspired to find a way to avoid the the depth. Um I guess.

SPEAKER_03

What's uh cluster?

Conor

Um they said they created a GitHub discussion. I believe that's probably on the Arraycast site.

SPEAKER_03

I don't know that's where we opened it then, I think I'm gonna Yeah, it does.

SPEAKER_04

Okay.

Conor

Oh, admittedly, it's not loading on my computer. Well, load for you, so yeah, we're on part two.

unknown

Okay.

SPEAKER_02

Okay, so this is the same thing exactly we had right. Yes, they add add open paren and do the do a negation and subtraction. It's just choosing which character you do, then doing a what's the plus thing doing the second plus?

Conor

That's a plus scan.

SPEAKER_02

That's a plus scan, but what's what's the other plus?

SPEAKER_03

Uh it's adding the original, I think it's Connors. It's adding the because this one keeps around the original mask, and then it gets added to the sum scan. Yeah, okay. And then yeah, you just replicate. Yeah, yeah, I think it's like the ones really have some shit. I still think that's a better way to do that. I don't know. Oh, because it's greater than one. Why greater? Then I've gratitude. Oh, oh, because it's yeah, okay, it's the eye mission.

unknown

Right.

Conor

Yeah, Marble Coma in the chat says uh didn't see the start of the uh stream, but uh not surprised that it's the same because it's a pretty natural solution. To be honest though, like if if I were not as array-brained as I am now, like the functional way to solve this coming from like Haskelland is to do like a split and then a drop, you know, first, drop last, and then a recombination.

SPEAKER_02

Um how do you choose what to split on the depth screen?

Conor

Yeah, you'd have to do that as well. But like uh Haskell and functional languages, to my knowledge, don't really have uh I mean I I I guess you could do like a filter after a zip with the depth if you wanted to, but like that's not where my functional brain would go to first. Like it like especially in Haskell when you have words and unwords, like you're very used to this kind of you know, splitting and recombining pattern. I don't know. You'd I guess you'd have to ask a I mean actually, Madeline, you're a you're a Haskell programmer. I think it would just be a fold. You would just do a fold? Yeah.

SPEAKER_03

After zipping with the depth, or I guess you'd just do a just a depth as a state and the result um just add if stuff to you.

Conor

Really? That's that's that's and that's your Haskell brain? That's not like your array brain.

SPEAKER_02

Um I have a fun solution then.

Conor

Oh, this is wait, wait, wait, wait. Let's let's do this Haskell thing first. Uh this is the first time ever for Raycast, episode 129, folks. If you're live on YouTube, you know what's happening, but if you're an audio listener, you're confused. We are at play.haskell.org. Didn't even know it existed, folks. Uh back in 2018 slash 19 when I was a Haskell fan. Uh I didn't I don't think this existed back then. And or if it did, I didn't know about it. And so we're watching live coded Haskell. We got monads, even though you might not know they're there, they're there, folks. And uh monetic functions? Nope. Well, yeah, yeah. Clash of the monads. That's what we should do an episode called Clash of the Monads. Uh although I guess it's kind of they're very simple on the APL side of things.

SPEAKER_03

Um thinking is if so we started at that zero, and then so if it's the XLM that is okay, so you have zero and and whatever, um x is and or something, we need to just do the same thing but increment so um like this yeah, so that's great and then zero. Um zero is a great, I guess it doesn't really matter. Um then if we have um and closing one, then uh one and closing is going to be zero and the same strength, and everything else is uh I think we can hear Adam's one and not come back later with the working association.

SPEAKER_02

Sure, I can I can share my screen. I've come up with a couple of interesting developments over here and experimenting, so we'll be the judge of that.

Conor

Uh maybe not if the screen never shares.

SPEAKER_02

Uh give it a moment. Give it a moment. It just um has to hang a little bit here. Okay, so a couple of things that I that I started exploring. One was let's just yeah, let's look at that first. Let's look at the at the depth depth vector that I've been working on. Um so we have been doing it, we did it before with like saying like the closing trend and then uh uh not behind minus. And uh sorry, get rid of this. It's just nice and short. Another thing that's nice and symmetrical is if we Like open parent or closed friend doesn't matter. So we want so equality that's all the open parents and unequality that's all the closed parameters. So we can write that as a nice fork. Like that equality minus the unequal unequality. I thought that's that's sort of neat. Either way, uh once we've we have the depth vector, we can go back to go back to this one. Then I did it with uh with petitioning. So so here's the depth vector. And if we then look at at the pattern here, then we can see if we should we can split every time there's a zero, and then every section and has begins with open and closed band that need to be eliminated. We can actually eliminate the closing one by using by exploiting the EPL2 partition function because it starts a new segment whenever uh we increase the value and and it discards anything that has a zero. So if we if we switch to um to the magnitude here, then we can see the pieces that we're going to uh to get. So now we can use this to partition t. So and all we need to do now is drop the first from each one and merge.

Conor

Oh, drop the first from each one.

SPEAKER_02

Yeah, because that's the opening parameter never got eliminated. The closing one got eliminated by the um but the petitioning having hit zero. So we can we can write all of this together as a tested function, even if you want, because this is just a behind this whole thing here. But there's a lot of monetic functions going on. We can write as a DN with here. And yeah, so this is a valid function. Here's a single monetic function, there's a datic function, an array, and a monetic function. So that's uh that that's valid. That's the trick. Um we can also write this, but there's a lot of lot of monetic function application going on. But if we go back to what I did before with the equal minus unequal, that comes out nicely and as a um as a dadic function. We still have to do a right check here or bind. We can stick the uh plus scan on top of the minus, and the result of the whole thing, we can we can put the sign. So this gives us this. Now we have a fork in here with a left argument and the right argument. So another another fork. We can bind the left argument instead, being that that's a derived function. This whole thing, a single derived function, not a not a train. We don't need parentheses over here either. So now we have a fully tested solution that is as short as the hybrid tested explicit one, which I think is the shortest we've got so far in the APR. Is it very readable? Maybe not, but uh I don't think it works. So this is partition diagram by where we have the sign of the equality width open for n minus the unequality open for n, and we've done this some scan of that, then drop the first of each and recombine.

Conor

What are all the different ways now we've spelt the depth vector?

SPEAKER_02

So it's got outer product, yeah. So the outer product one, right? So we can say so depth outer is open closeprint jot dot equals the right argument. Yeah, we got uh depth separate, we would just say open print minus closeprint, which we can we can make that look nice if we put uh that's nice and palindromic sort of like that. Um we have done it with a negation or like a not. So we just look at the close print in APL because we only have a one hook operator. We use the close printer for that. We could actually use the open print and not equal as well, doesn't really matter. Not behind minus. So this isn't even the whole depth, right? This is only getting the um this onto with onto the subtraction. So this this is missing, I think. There we go. Now they're all these are all equivalent here. Yeah. And um do we have another way to do it? Well then you just had your late equal not equal fork. Yeah, but it's the same, okay. Sure. So dfork, if you want, which is open parent equal minus unequal. Oh, here's another one we can do.

SPEAKER_03

Can you do something one minus two times? I think that works.

SPEAKER_02

Uh one minus two times the the right side, you mean? One minus two times closing equals. Yeah, that's just the mathematical way of expressing the same thing. One minus is a knot. Oh, right, it's just the same one as the knot, yeah, yeah. So but yeah, I mean that's that's valid. But I just realized now that everywhere we've been doing open for n, that's sort of not very elegant because we know the first character is an open paren. So we can actually write write it in a neater fashion. If for example, this one, so let's say we have t, we know that the first character t is open for n. So we can write uh first unequal to the whole thing, which is a behind. Look at this behind here, right? And then we do the not behind minus on that. Yeah, that's really nice. No constants involved, and it works for all types of brackets now. That's nice, and then we do the scan and so on. I like that better. I really want the last primitive because in this one it would be it'll be nice to do uh first and first equals minus the last equals. But of course, we could just write first unequals if you want. So this is another way to do it. All look sort of symmetrical, but this needs parentheses. There are many ways of spelling things because these do too many comparisons. This this should be the fastest. This or with the constant, it doesn't matter. Because a Boolean negation on the mask that's going to be very fast. So I think I prefer this. So that that's one part of the problem is get to the depth vector. So far, we haven't come up with any good solutions that doesn't need the depth vector. Um, or any solutions that don't need the depth vector.

SPEAKER_03

And have the house code when you show it.

SPEAKER_02

Yeah, you want to show it?

SPEAKER_03

Yeah. I just forgot how types work, but uh okay. So yeah, it's just basically a fold. You keep around the current depth and the result as a state, and then you just fold over the string. And so if it's zero and it's opening, then you want to increase the depth but not add anything to string. Um, if it's one and it's closing, you want to decrease it and not do anything. Otherwise, you just add and increase and decrease based on what it is. Uh then you just pick out the the string and you reverse it because you append it instead of yeah, prepend it instead of appending because it's faster, and then you spread. You can probably do with a right folder as well, it's probably better. You can just do this, I think. Uh you don't need to reverse because you're just bending it up the other way.

unknown

That's better.

SPEAKER_03

But yeah, it's not a good selection, but I think that is how I would approach it in a screen. I think this works as well. No, uh, whatever. Uh because I have to reverse opening and closing it. But uh no, I don't think it would look good in any array language. Uh yeah. I mean so you could I mean I can try writing some tiny. Uh so then I want to make a folding string. Let's just make a different thing.

SPEAKER_02

So I want to check if it's you might not want to do it user fold, you might want to use loop over the order elements instead. It's easier.

SPEAKER_03

What do you mean?

SPEAKER_02

You're just carrying the state, right?

SPEAKER_03

Yeah.

SPEAKER_02

So you can just have a state variable.

unknown

Yeah.

SPEAKER_03

Well, they don't already have a way to do loop so they don't fold in. Um I guess you could use uh an LTL, but that's not gonna look good, I think. Uh no, there's no good way to just make a loop. Let's bring more lines up on some idea. Then if it's one and closing then return zero and if it's um there and so I guess oh I can make it side synchronized. I think if just return um the first one plus uh I guess minus one omega's closing. Uh and another one is going to be uh omega second one. Um I don't know. But yeah, and it it's definitely not going to be pretty. Yeah, I don't know, but yeah, it's definitely worse than the array once. But I think there's a good way to spell the array once in Haskell. So I think people usually just make this fold. Maybe with a boolean like checking for equality first, maybe I would do that. So the function's total. But other than that, uh yeah, I don't think there's a better way.

SPEAKER_02

I'm I'm working on some state machine thing. Uh I can show you, but on Disney again, not going to be it's not a APLE, yeah, but it's it's more a general purpose thing you can do. Uh see the computer gets around to sharing. So so here we set up in an initial state, an initial and a result accumulator, and then we do our just use the fork here when passing in the open paren. And this is the the whole array. So this each is actually looping over the left argument. All right. Um and just passing that in. So if we so if the equal minus minus unequal, that's the what we what we did before, and and then we're testing the state. So if if the state is zero, um again, if the current state and the current character is zero and open paren, then uh we want to eliminate it. So which means if they so this is eliminate, we're just gonna write that for now. And the other case is if the state, oh, it's not you, it's one here. And if the state and the left argument is a zero and a closing paren, that's where we should write this out. It's going to be selected like this. Okay, so if the state and the um and the current character that is one and open paren, we want to eliminate it. If the state is um and the current character is a zero and a closing paren, we want to eliminate it. So now we can say if this is a member of one of these two, then we want to eliminate it. Which means we can take this and we can especially use it behind there, just for good order. Which means if one of those are true, we want to drop from the current character that we're dealing with. And I think we don't even need to, we don't even need to update an accumulator there because this just gives the budget. There's empty vectors and nuts. Now we just enlist that. So that works. I suppose that's sort of philosophically sticking the same thing that you're doing in NASCAR, even though here I'm carrying it an outer state, so muting this, but yeah. So I suppose we could do this. Uh yeah, we could do this as a reduction. It's going to be the same thing, but it's just going to be more complicated to keep track of things. Also, this is completely unreadable. But actually, we can we can state some logic, right? If it's yeah, if it's a one and open paren, a zero and close paren, that's the same thing as saying that it's equal to the open paren, right? No, because it's not a movie. Yeah. We could we could separate this out and say if uh if d is less than or equal to to one.

SPEAKER_03

You could probably do the index of d in one zero is equal to the index of omega in open close. No, because that no, I think that's good.

SPEAKER_02

Oh, but we could say this, right? It's we can we only want to eliminate it if d is less than or equal to zero.

SPEAKER_04

Yeah.

SPEAKER_02

And we also want to eliminate it. The other criteria is that yeah, we can that doesn't really work, right? Oh, right. The other criteria is that b equals this is fun. Omega equals open brand.

unknown

That's fun.

SPEAKER_03

You don't need the less than or equal to one, because then it's definitely going to be false if because these are yeah, if d is true right, then it can't be true, right?

SPEAKER_02

Yeah, exactly. So so it has to be. That's the only case. So there we go. That's nice. Which means there's only one there's only one D left. Uh yeah, well, we have that. Yeah. That's nice. We could do an something very unusual. We could do an equal reduction. That doesn't it's not shorter, but it's cute. And this one we can go back to what we had before. Shorter. Oh, did we make a mistake?

SPEAKER_03

Has to be a closing card, yeah. Or unequal. Yeah, or you put the negation on the other side, but then you need the self. Yeah, self reading dialogue. Yeah.

SPEAKER_02

Yeah, so this is this is a real state machine. This is the state, the depth. We're updating the depth as we as we go along using our one of our many methods of of doing this. Um, and then you know we do it. But I mean, this drop thing is a bit of a a bit cheating. Like really, what we should do here is we should say um we should collect instead. Either we can have an accumulator, so we'll put that in here, and then we say r, comma, gets that. Then we don't need to do the the in list, that's a more general solution, or we can uh get the mask out. I mean so we just we just want to find out what what the mask is here, so and add to the mask. These are the ones we want. This is the opposite, right? Because of the quality here. Um that's fine. We could flip the nut, or we can do some clever things here. So I think we have to do like this. There you go. And now we can use the mask. That's a state and um accumulator.

SPEAKER_03

Yeah, I mean you don't really need um we just return the boolean from the eek. Oh yeah.

SPEAKER_02

Of course, we have that here. Of course, send me. So this gives us the Boolean, and we could just do that. We don't need to satisfy them at all. Which means we can do it behind.

SPEAKER_03

Yeah, I mean it's not good, but it's neat, I guess.

SPEAKER_02

Yeah, yeah, it's going to have horrible performance. Now I'm thinking now I'm thinking instead of initializing D like this and having like nested, what if we can we do this? Can we store a state? We start start with a state of zero and we use a function that lives inside here, and we update D as we go along. That works.

SPEAKER_03

Yeah, sure.

SPEAKER_02

But you can only use the function once, and you have to reset it.

SPEAKER_03

Oh right. Well, no, it can't be zero at the end, is it not? If the string is valid.

SPEAKER_00

Oh uh yeah, we live yeah, you're right. Uh it happens to be that it works. Yeah, so we can actually use this.

SPEAKER_02

Yeah, you can say it resets itself when it's done. Very nice of it to do that. Carla, you're following what how this works? This is using lots of interesting features, you would say.

Conor

Uh not really. Go ahead. And uh we lost Carlos.

SPEAKER_02

Okay, so so this is a behind, right? Where we uh this is a classic or oft-repeated pattern by me, where we are have a function that is in that computes a mask, and then we're using that to filter. So filtered by this function. Now, this function, which is here, uh well, actually the whole function is here, but we're going to apply it to each character. And the function lives inside a namespace that at definition time had a single member D that is zero. So it's an object, right? A state. But this object, this state is not observable outside of f. There's no way to access it whatever, other than like doing a memory dump, something like that, looking at what's in memory of the computer. So this function operates inside this namespace. So when it refers to D, it's the D that's inside this namespace, and it mutates that. So we're using our formula from before to update the state. This is the same, this effectively for every character gives us the the running sum of uh the subtraction of the auto product and that we did before. But we only entered it for every character in the state at that point. So we we update the state for this character, and then we do this little bit of clever thing here. Uh we I can expand this again. D is different from this equals this. Right, then we say this is the current character an open paren. Then we want to keep it only if the current state, so that's a one, only if the current state is not a one. A one with an open parent, that's what we want to eliminate. And if it's this highlighted part here, if the right argument, the current character is a closed parent, like this gives zero, then we only want to keep it uh if the current state is not zero. Because if you have a closed parent at state zero, that's zero, then that's what we that's an outer one, and we want to eliminate that. So this gives us a Boolean mask for every character, whether or not we want to keep that. And as Madeline correctly pointed out, where we know that everything is well balanced in a string, which means that when we reach the very last character, which will be a closing parent, and will be eliminated, and then the state, the depth state is back to zero. Because we always increase the depth nesting depth and go back again to zero scheme, which means that the function is ready for the next invocation. Now, if you run two of these in parallel, then they might get might get mixed up because they have the same state. Uh I'm not sure if we can induce that, but maybe. I think so. I think we can actually force that to happen. So if you do like T and we'll make another one. T2, like this, and then we can do if you run F in the background on T, that should print. Yeah, and F in the background of T2, that's fine. So if you run it on both, oh sorry, I'm gonna call it that still works because it does the whole run. But if we redefine this to insert a delay of like a tenth of a second or something, then they could possibly get out of sync. I think, yeah. Now we get a messed up result because they they stump on each other's state, statefulness is bad.

Conor

This reminds me of the quote just because you can doesn't mean you should. No.

SPEAKER_02

Absolutely. This is not how you're supposed to do it in an array language. But there are things that are not easily done within just by computing vectors and going on. Sometimes you do need to compute a state as you go along. And then this is sort of a general method. I'm not sure you should do it with a namespace, but what we did before, when we set it up. This is a general way to do it in every language. It does require mutating things at least in a global variable.

Conor

Alright, last thing while we wind down, you should take a look at the caps. I converted your APLs dialog APL solution to a cap solution using the using three different behinds. Uh the links in the bottom of the YouTube chat.

SPEAKER_03

That's uh this one coming up over here.

Conor

Oh look at that. Emoji rendering.

SPEAKER_03

What? That's the old one, I think.

Conor

That's the old one.

SPEAKER_02

There's a new one? There's a new one. Oh looks the chat did not date for me. Maybe I haven't been seeing people's comments and things, because I don't see I don't see anything since you wrote the cap is very beautiful.

Conor

Uh here, let me I can message and mess up our live stream the chat, and then you can click on it there.

SPEAKER_02

Or you can just share.

Conor

Uh I could, but that would risk it's coming.

SPEAKER_02

It's on the way. It's in cyberspace. No messages yet.

Conor

Oh yeah. I was gonna say I guess I could've just read to you the four character hash code. Yes.

SPEAKER_02

But so this is the one?

Conor

Yeah.

SPEAKER_02

Well it hasn't it hasn't updated because there's something about the URLs, because it looks like an ID, uh it tries to jump to that heading. So I think I have to put it like a new window for it to work. That might be a deficiency in the design of a RainBox.

Conor

Is that really how it works?

SPEAKER_02

Because you're using a hash there instead of just using a slash or some other character, and you're using it to read, then you can't switch it when you're on already on the page. The browser thinks, oh, you just want to jump to a different location in the same document.

Conor

Wow, that emoji rendering is so aggressive compared to my emoji rendering. Mine's very I think mine's the iPhone soft. Yours is like the Microsoft software.

SPEAKER_02

Depends on the operating system and the browser and so on.

Conor

Well here actually, I this is the beauty of uh I can I can drag and drop my little thing so people that's that's my emoji, which is m much cuter than uh the Microsoft 3D one. Anyways, this is the You just need to add the emojis to 37, I think. Sorry?

SPEAKER_03

We just have to add the mojis to APL37.

unknown

Yeah, yeah.

Conor

Well, we do do we agree on which rendering though?

SPEAKER_03

It's probably uh No, then the what we just compose them all with little bases.

SPEAKER_00

If if it was then they should be like line line drawing art.

Conor

Honestly, it's obviously you were joking when you you said that, but there's actually something uh behind using uh APL glyphs to render, like you know, you got a f four different glyphs to render uh the different you know, you can do all of them to be too much work, but you could do a few. Uh anyways, this is yes, the dialogue APL converted to cap, which is a little confusing because they switch up some of the symbols on you, so it it makes it a little bit harder to read.

SPEAKER_02

Yeah, so this is this is the uh the petitioning thing.

Conor

If you hit F1, hit F1, it's beautiful, beautiful. Look at that, folks. Look at that.

SPEAKER_02

Petition, right? So it uses the AP uh APL2 uh pairing of glyphs. So and this is first, right? That's for the same reason as an APL2. We could make it look the same in dialogue if you wanted. So yeah, that's this is exactly the same, right?

Conor

Yeah.

SPEAKER_02

It's literally just no. Oh, this is tail, right? Yeah.

Conor

Yeah. I thought it was called behead, but I think it's only called behead in J.

SPEAKER_00

But in in the in the ducks.

Conor

Uh no, I think it's confused because your cursor is to the left of each, but if you just put it to I don't know, that is actually a bug. That should be highlighting drop first.

SPEAKER_02

Um first.

Conor

Although interesting. Actually, let's diagnose this bug. Put your cursor to the right and then shift left, and maybe that's what it is. So it reads the cursor. That's oh that's what I did.

SPEAKER_02

That's really wrong. It forgets to look at the direction of the selection or something. But in anyway, if something is selected, it should go by the selection. Don't care about the code.

Conor

It's supposed to work that way. I don't know what it's doing. I'll file a bug on my own repo.

SPEAKER_00

You didn't you didn't write the code, right?

Conor

No one needs to write the code any day any anymore, you know. We're we're all just handcrafting uh APL code now, but the rest of it, if it's JavaScript, send it to the AI.

SPEAKER_02

So having drop first does the trick here.

Conor

Yeah, that's what I was also thinking. I wasn't gonna code this one up, but then I was like, oh wait, doesn't uh cap have behead?

SPEAKER_00

Uh and you have that in tiny apple?

Conor

Yeah, no. Ooh. A missing primitive, a missing primitive. The people demand all the primitives in Tiny Apple.

SPEAKER_03

Even Jay has behead. Yeah. Well, I thought that's the other one which is nighter, the minus one drop. I use that one more than one drop. Kurtel. Yeah, Curtel. Interesting.

Conor

Here's a last question too. Is is oh I think it's a Google, I think it's a Google Share. I was gonna say there was like a slight Phantom help uh doc that I could see, but I I think it was uh the screen sharing software and not actually the website. Um anyways. Alright. This is this has been fun. Uh thanks to Marble Coma. Oh, uh my my chat's gone. Oh, there it is. Thanks to Marble Coma for sharing their uh Weevost solutions, and thanks to Madeline for coming on and showing us not only Tiny Apple, but also Haskell. Like I said, a first folks. That's why we need to grow the panel so we can get more functional languages on this array programming podcast. Any uh any last things uh to be said, to be to be done? If not, going once, going twice. With that, we will say happy array programming.