Conor

Welcome to ArrayCast episode 125. I am your host, Connor, and I'm here today with the only panelist, therefore co-host for the time being. Adam, I guess we'll go around just for old time's sakes and do brief introductions, and then we've got two announcements, and we've got hopefully a fun topic, maybe a little bit different because we've got this YouTube format. But before we get to that, uh we'll do a brief introduction from Adam. Right, I'm Adam Botsewski.

Adam

Um I've been doing APL my whole life. I I do APL at Dialog Limited, where we create the APL of the future, I could say. And I'm I've been honored to become the head of language design there, but I also deal with everything else dealing with the language at dialogue.

Conor

And as always, I am your host, Connor, massive fan of all the array languages. And yes, we have two announcements I day, uh I believe today, both from Adam. So I'll throw it over to you and then we'll hop into our conversation.

Adam

Um right, so I unfortunately had to announce in the last episode that uh Kitty Christensen, the former CEO and uh um of Dialic Limited, and much of the reason that we've been here today, uh passed away, uh, there was a uh a funeral service for her. And there's also been set up a uh a memorial site where you can both uh see a lot about her and uh bituary and and other things, but you can also add your own tribute. I'm sure that a lot of people want to do that. So it's gittercrestens. And we'll leave a link to that as well. And then uh there is the APL Forge, which is uh the thing we do a dialogue every once a year, um where we let people submit um projects that you started in or for dialogue APL, and it comes to an end once a year, and then we start a new round, and there's one month left of this year until we stop at the round and there's the next round. And you can still if you have some kind of cool thing you made in APL, um then you can uh still um submit it and then we'll have a look at it, and you might win a price and um a trip to the next user meeting. So have a look at uh forge.dialog.com.

Conor

And we will have links for everything that just got mentioned in the show notes. And surprise, surprise, we have now a second panelist, or technically guest. I mean, you are listed on raycast.com as a recurring panelist, so I guess you are a panelist for today. How's it going?

SPEAKER_00

It's not bad, it's not bad, kind of thanks.

Conor

You're popping into a live stream on YouTube, so I'm not sure if you've heard, but things are things are different now. You know, there was the before era, now there's the after era. And in this after era, uh we just uh You just go straight there. Yeah, it's mostly laziness, I guess, because Bob was doing a lot of work back in the before era in a raycast 1.0, and Adam and I wanted to keep on keeping on, but I did not have the time to uh put the amount of effort that Bob put in. So we said, What uh I thought to myself, what's the easiest way? And I was like, wait, in Tacitalk, I just live stream, I do a little bit of post-processing, and if AI gets good enough, maybe it'll actually it'll never reach Bob levels. But you know, maybe the ums will get removed and the the dead air will get removed. And uh, anyways, um it's good to have you here. And in the chat, we've got uh multiple hellos. Well, one person saying hello to the chat, but also Max, aka meme god, saying, Wow, it's rich. You know, he's uh Is that Max? Sorry?

SPEAKER_00

I saw him not long ago, so yeah in in real life.

Conor

So hello again. I also saw him not long ago. I mean, he's local to Toronto, so I guess it's probably easier for me to see him than it is for Right.

SPEAKER_00

I had to fly a long way.

Conor

All right, well, you joined just in time uh for a little bit of a different episode. So Rich, I guess, has no idea what's about to happen. And um, Adam got, I believe, if you include the time when he was reading the announcements and introducing himself, a grand total of like 10 minutes to ruminate about this problem. But we're gonna uh chat about a toy trivial uh problem from Pearl Weekly Challenge. We actually don't know the number. If for whatever reason this gets back to the Pearl Weekly Challenge people, uh you clearly vibe coded, which I've got nothing, I'm I'm a big vibe coder. Uh I love vibe coding, but they vibe coded an upgrade to their Pearl Weekly Challenge website, and it is no longer clear to me. I mean, I spent like three minutes, that's why we were a bit late starting this episode. I mean, the podcast people and the audio players have no idea that we were three minutes late, but the folks on YouTube know. And we couldn't find the the past uh problem links. Anyways, I happen to recall the problem from memory, so this was in the last like month or two though, and I never actually solved this problem. I read it, I thought about it, and then I couldn't find an or think of an elegant way to solve this. It's definitely solvable quite easily, but like I couldn't think of a kind of single one-liner tacit solution because there's a kind of a couple edge cases. So here's the problem. And I'm not sure if at some point uh I want to share my screen or screen or Adam wants to share his or Rich, you can even share yours.

SPEAKER_00

I'm on the table of problems now on the on the weekly challenge site. So once you describe it, I think.

Conor

Does it is it the one that says recap, or is there like a link to because the recap one just No no slash challenges?

SPEAKER_00

So it funnily enough, in the title bar, it's under the tab this week. So that's the one I went to.

Conor

That's the one I went to. And then I would think, oh, it's just for this week, it's actually past weeks. But when you click on recap, it doesn't bring you to the problem statement. It just shows you how many languages it was solved in.

SPEAKER_00

Oh, I see. No, no, I'm not that far. I'm just at the table of Yeah.

Conor

Look at that though, like the UI experience here, two different people completely unrelated, did the exact same thing. They they found the challenges under this week, thought that's a weird place to put it. And then it turns out uh, first of all, it's not for this week, it's for the past weeks, but it doesn't actually show the problem description.

SPEAKER_00

It's an abbreviation for this and all weeks. Yeah, obviously. Uh go on, describe the problem. We'll we'll see.

Conor

So the problem is, and it may be someone in the YouTube chat, because we've got a few viewers, um, and and play along as well if you're on YouTube doing this live, and also if you're listening to this in Spotify, Apple Podcasts, whatever player you use, you're given a string of lowercase characters, and you want to return the largest distance between two equal characters. So two characters that are the same. And if there are no duplicate characters, so there's no two characters to find a large distance between, uh, it is you return negative one. And you it's exclusive of those two characters. So the easiest example is, or a couple examples, if you have the string A, B, C, C, B, A, the two characters that have the largest distance between them are the a at the beginning of the string and the a at the end. And because there's B C C B in between those, that's four characters, so the answer is four. If you have the string AABC, there are three pairs that all have the largest distance, which is zero. And if you have the string ABC with no duplicates, you return a negative one. And so if you want, we can ignore the negative one uh for a while. But even just the uh, you know, assuming that there is a duplicate, how to well actually I guess the negative one is the tricky part because if you were to do something like my uh my thought process, and then I'll let the pros uh step in, was that you want to use where or indices to do this. Um something, well, is that actually true? Or classify? I can't remember now that I I I guess I should have uh, but there's some operation basically where you want to get um well actually uh okay, I gotta step a step back. Let's actually walk through this if I'm solving this for the first time because clearly I've forgotten. I think at one point I was like, let's do an outer product. If you get a unique with the um values in your or the characters in your string, you can then get like a uh matrix where you have a mask that corresponds for ones for all equal values, and if you did an indices on that and then some kind of um you know two y's minus reduction, you could then get the differences, but then you're gonna run into issues with that. And then I I I think I had an alternate version with where, but it still wasn't great. And the problem is that if you are going to do the first last trick, so if you even if you take that matrix index idea and you look at the first value or the first index and the last index, you're not gonna get the correct value if you only have a single character in the case of the ABC string. Uh because the first and the last both point to the same one, and they can't both point to the same one, right? So you have to do some kind of check to make sure there's at least two indices that correspond to equal values. Um and yes, someone in the chat.

Adam

That's just checking. Like you know that that if they have the same if they have the same position, right? Because it's the f the first and left are the same, then the distance between them is going to be zero. So it's only a problem if there aren't any duplicates at all, right?

Conor

Correct. Although now that's super easy to check. We have to subtract what I think is like a difference of zero already is invalid. Like it has to be a difference of yeah.

Adam

So you just if there's if there's I mean, if this a just simply because a then the answer is zero, right? Are you still looking for it?

SPEAKER_00

Oh yeah, yeah. Uh some of the comments says straight oh largest same digits number, but I'm not sure it's that.

SPEAKER_05

Uh but hold on.

Adam

Uh let that's just just to think about this. If if the string is aa, then the the first and the last indices, right, should be one apart. But the actual answer we should give is zero. So we just subtract one, right? Right. And then the one that's a little bit different. Now the only way to get the only way to get the largest distance being zero if if every character is unique. So all we need to do is subtract one and then we get negative one. Isn't that super easy?

Conor

That's so sad. Yeah, yeah, yeah. So this corner case that I thought made it tricky, it's actually super simple because you're gonna have to subtract one from everything, and the case where it's zeroed actually gives you the exact value that you need.

SPEAKER_03

So I think that I have a solution in in dialog API.

Conor

If you want me to share my screen.

SPEAKER_05

Yeah, yeah, yeah.

Conor

And so there was someone in the chat that was mentioning a different problem. It definitely wasn't that problem. Uh and yes, we were saying that we pro weekly challenge recently vibe coded their an upgrade to their website, and we can't find a list of the last problems. The hack that I was doing is if you go to this week, it shows you a full URL with uh weekly or week 374. If you just change those URLs to 373, 372, 371, which is what I was doing, but I couldn't figure out. Um, I still couldn't find the exact problem statement. But it was in the last month or two. So if you uh you know YouTube viewers want to go and try and find the link, paste it, we will we will then share it with folks. Uh we don't know which week this is.

SPEAKER_00

I was immediately thinking uh Adam's sharing a screen and it's got the the key operator. As soon as you described the problem, I was immediately thinking key in my head. Um where the default gives you the indices where unique major cells and in this case unique elements occur. And that's that's what you're concerned with, right? So the indices of elements.

Conor

Yeah, well, I was concerned that if you like, like I said, like it's actually ironic that I thought this one was tricky because the problem statement actually is perfect in that getting the negative one is a natural byproduct of actually subtracting one from the deltas between the indices. So like what I thought, and I thought that was the tricky part because you had to deal with that some way, but it's actually it falls out of just dealing with the the general case. And uh the interesting thing is though that both of you thought of key, whereas I guess I don't reach for key rarely ever. I always think about I don't know.

SPEAKER_00

Doesn't do a lot of groups.

Conor

You basically said it, you said classify, right?

SPEAKER_00

Yeah, you said classify, and that is what it does.

Adam

Classify is not an APL though, so this is it fulfills the same role, right? It takes these and puts them into takes all the A's. So the way I thought it was key anyway, because we're not interested in A in relation to any other letter than A.

SPEAKER_00

So classify was that the once upon a time a monadic equals in some writings that would give you that matrix. It's like a character. Yeah, things matrix. Yeah, okay.

Conor

Yeah. So this is exactly what I said, right? I said, yeah, like a unique uh this is what they had to do before key. Ease before key. Yeah. So actually, so let's this is amazing, but we uh like I'm very excited because this is I you know, uh did we have a topic for today, you know, uh Adam and I were trying to figure out, and I was like, well, what are you talking about? I know, I know, but I thought in my head, I was like, well, there's not anything like topical news or and we didn't have time to set up a guess because I've been I've been out of the country for the last uh week. But I was thinking, you know what I actually want to do is I want to ping, I want to I want Adam to solve this problem that I like in my head a month ago couldn't like come up with an elegant solution for. And now we've got like three different solutions, or at least two. Uh, but let's so let's take a step back and walk people through the uh the first uh and so someone I think has found it. Task two, they haven't mentioned the day, but the exact wording of the problem is you're given a string, write a script to return the length of the largest substring between two equal characters, excluding the two characters. Return negative one if there is no such substring. So I I stated it slightly differently, but it was just an alternate description of the same problem.

Adam

The only problem is if it's empty, then things will end up.

Conor

D Z and Naroli, if you'd like to say what week that was. Um yes, that is the exact problem that we are talking about. If you say the week, we will uh we will mention it for the audio listeners, obviously everyone on YouTube at this point. So yeah, walk us through starting with key, because I'm sure there's people in the chat. Uh because like I said, I I rarely reach for key, but it is in this case exactly what you wanted.

Adam

Yeah, so let's take this this simple example here. We've got uh ABCAA uh with key. And uh we're just going to inspect what uh what the elements are going uh are going to be. So the way it works is the key uh what the argument is going to be. Um the key will classify well, it will it will take the col the um array on the right as a collection, and it will punch together all the equal elements, and it will call the function on its left with that element uh or that um that major cell really uh as left argument, and the right argument is going to be the list of indices where those appear, right? So we see A appears at these places, b at these places, c at these places. Now we're not actually interested in the element itself, so we can get rid of that. We're just interested in the in the indices of individual um elements, and then we wanted to find the location of the uh uh the largest and the the first one and the last one, and then subtract them. So this is the so the max reduction and the min reduction, and subtract the two.

SPEAKER_01

Wow, you walk people through that. I assume they uh know a little of AP, but they're shocked by you.

Conor

Whoa, what is this incantation that you managed to okay?

Adam

So this is the fork. So this is the the maximum reduction on the list. This gives the last time anything appears, and this is the uh minimum reduction, so the first time it appears, which could be the same, of course, if there's if there's only one.

Conor

And to be clear, the reason you're saying first and last is because a property of these indices is that they're gonna be sorted.

Adam

Uh yeah, of course they're in there, they're sorted, they're sorted there. But it doesn't matter, even if they weren't sorted, I'm actually not getting the first and last. I'm actually getting the maximum and minimum. So I can actually make this shorter matter.

Conor

It's the maximum min glyphs, but you were saying first and last, which yeah, it's going to be the if you're not staring at the screen. Uh you could also in a moment for that reason.

SPEAKER_00

Uh what do you say, Richard? You could use first and last in this case for that reason.

Adam

Yeah, it's just it's but it's sorted. It's easier to reason about it like this, but but we can change it to then and we don't have a math if you're gonna do first and last because it wouldn't be able to compute anything.

SPEAKER_00

That's true.

Conor

We can go half later. Well woo, half later.

Adam

Uh okay, so and and what happened over here is basically just in mathematics that if you've got uh f of x plus uh g of x, then you're allowed to write that as f plus g of x. So I use that over here. So this is the the max of the right argument minus the uh min of the argument. So that's what's happening here, and that gives us that gives us these. Uh we don't actually need the enclose anymore because they're all scalar values. Um and then we wanted to uh subtract one, so because we consider adjacent as having a string of length zero between them, so that gives us all these, and then we want to find the maximum value, and if there are only negative ones, of course it becomes negative one. So this is the this is the full solution, and this can be written locally in a tacit way as well. Uh so we can try that, and then we can try it on these. Um and now because these are max, I mean actually they're actually sorted, we can replace the in the in Dalegap, we can replace the minimum with the first cliff, which is fine. Uh it doesn't really matter. Um And there's some more things we can do. We can because this is just applying a function on the argument, but we had it has to be the right argument, so we can just say that we apply we composing these at the top. So we say we want this function applied to the result of uh the function that selects the right argument, it can also the left argument. So that's this also works. Uh it would be so nice if we had a last glyph, wouldn't it?

Conor

Maybe later we'll I'll solve this. Well, I'll attempt to solve this in Tiny Apple because not only do they have uh yeah, the first and last, but they also have I believe Classify, which there's yeah, uh Rich is in the chat. I was also thinking the same thing. So Max has said that IOTA self uh is classify in BQN or swap. I'm not sure which one it is, but Iota is um not in uh BQN. They have the range glyph, but I'm pretty sure classify is actually one of like the I can never remember, but they they have like the claws or like the open boxes on their sides and the underbar open boxes on their sides. One of those I'm pretty sure is classify. And in fact, yeah, this is classifying, right?

Adam

That that's the I think that's what theme god is trying to say. So here I'll put in the I'm not sure if uh the uh so you want to you want to group by the classif self-classification here, right? Um that's another way another way to get the the indices here, but uh but key is of course very nice. So there is a participant in the chat with a name that I find difficult to pronounce, spelled underscore underscore dash kd eight o z or is it e depending on the s. We'll just call them ours. Kd eight oz. Um uh and uh try to translate it to J that looks to to a j solution that we can I can put here in the just paste it in yesj if we were on Ray Box we could actually evaluate it. But I this seems overly overly complicated because J has key.

Conor

Now I'm not an expert on using it, but so wait, wait, let's walk because this is exactly this is interesting, right? This was the and we're gonna solve this in dialogue APL this way as well, because you before I said let's slow down and walk people through the first solution, you showed the unique without a product, and the next step would be to do like an indices on each of the rows. And my j foo is not great, but basically that's what that looks like, right? You've got a I yeah. So if we do if we do like a unique um the U Oz just said uh it's a randomly generated name. Don't let it befuddle you. And the thing is that I don't know how to use key and j. So here we go, folks. We're taking key and j for a spin, although we're still in dialogue EPL. So we'll we'll get dialogue.

Adam

If you do the indices here for these, so we want each row, we want to do the max index and the min index, right? That would that would work as well. So we can s we can try this. So on each row, we want to get uh the uh the index of the la uh well, so we want the indices and then we want the max minus minus the min, which is of course the first and the last, the same thing. Like this. So that then we're up to the step and we can continue from there.

Conor

Can't you I guess right, you don't have but technically you don't have uh cells, like you don't have a shortcut for rank one.

Adam

No, but it wouldn't help much either.

Conor

Right. I was I was gonna say I was thinking is there some way to do the shorter, but I think this probably is the short.

Adam

There is because you can you could do you can do trickery with nested arrays, we can do this, right? Because of how Net how um scalar functions penetrate into structure, so then we make the whole thing a scalar, and then we get the unique, which is another vector. So vector equals scalar, it gets the whole scalar gets paired up with each one. So now we've got these three, right? So those are just the rows of this same thing as splitting this into its constituent cells, and now the rank one has magic.

Conor

You just you just blew through this.

Adam

Whoa, so now we can just do an each on this instead, and we get the same thing. So that's slightly shorter.

Conor

So step back to uh so you've got in a fork unique equal enclose.

Adam

Yeah, because if you think about it, if let's start with not unique. I'm thinking about it, but uh and and uh an identity function equals the in-close is so the in-close makes this whole thing into a single scalar, right? It's a nested scalar, but it's a single scalar. So now we've got vector equals scalar. I mean, so we know the result will be a vector where we take this entire scalar and pair it up with every element of the vector. Now the every element of the vector was those original letters. So we compare every letter with the entire vector. So that gives us this. This is the outer same thing as outer equality, but in a nested form instead of a rank form. And if we replace the density function with the unique elements, that's the same thing as the outer product, but in nested form.

Conor

So this is that is beautiful. That's the same thing basically as a mix of the outer product that you have before, right? That's a split split split of this or mix of this, right? I can never uh I can never keep which ones.

Adam

So a split of split splits it into individual uh rows and mix mixes together the rows into a single array, right?

Conor

A single yeah, and technically you can put the split into the the tacit expression up there, and you can do the same thing. So really it's there's no point I know, but it's a two like if you want to assign these to a function. Oh actually, yeah, and then and but if you're and if you're golfing, this is basically like a two-character saving. So if you ever find yourself uh splitting uh oh right, then you can outer product.

Adam

If you actually want the outer product, then it's shorter to write this than it is to write the equivalent, right?

Conor

You save your one character, even though it's very silly, and it just looks beautiful, like the the rotated rotated horseshoe.

SPEAKER_00

Oh my god, the the the forks that look a bit like faces, yeah.

Conor

I mean, I can't. I don't know if I can see an expression this guy, it's elegant as hell.

Adam

Okay, so so and then we're just we just do the each here, right? Because now we have a nested form, we don't need to do rank one. So we essentially got the major cell cells for operator because now we're just operating on uh individual elements, and being that the result of this is a simple scalar, it all just collapses back. This wouldn't work in the in a boxed array model, but it does work here uh because of uh dialogue APL's floating arrays. But there's a there's more we can do actually. I was just thinking here because if we look at if we go back here and look at this, there's a fun thing that we actually just want uh the the largest one and subtract the first one. So uh what if we could find the position of the last one in a more direct way? And the position of the first so the position of the first one is actually interesting, right? Because that we find here. The position of the first A is one, the position of the first B is two, the position of the first C is three. So I mean it doesn't matter that we're doing the computation multiple times. How can we find the position of the last one? Well we can sort of do it by uh looking into into the reverse, but it's not quite, because then we get the position from the end instead. Okay, so so uh one is this one, and then then the B we find at position five, but from from the end. So if you subtract this from the the total length, then we can see that the last A is in position five, one, two, three, four, five, actually six, but off by one because we cut counting positions here compared to the um, but that doesn't matter so much. So this gives us the last position, and this gives us the first position, which means if we subtract the two, and then it will be the wrong uh the wrong uh sign, but that doesn't matter so much because we can easily just swap things around here. Oh sorry, did I do the wrong thing? Uh sorry, it should be like this instead. Is this right? Yeah, these give negative one, right? Because those are the ones that don't have any duplicates, and then we just want the largest uh value that we've got here. So one, two, three, four. That's the distance over here. So the the off by one error came to our advantage. We don't have to do that adjustment. So this is a this is a solution where we directly look for the first and the last, and we don't do the whole key thing. It's probably faster. In fact, we we wouldn't actually need to do it on all of them, we could just do it on the unique ones, but yeah, that's fine. Do you need to go through it again? See what just happened here?

Conor

Well, and also this is only a solution for a subset of the problem, right? It doesn't handle the negative one case. Why not? You see, the negative one came out here.

Adam

Yeah, because we come.

Conor

I got three different selfie slash commute squiggles. This looks like absolute nonsense. Uh you you're the one that liked the combinators. No, I know. I say this from a place of combinator combinatory logic love, folks. I'm just saying we were we were dealing with the beautiful, unique equals enclose fork idiom that I just learned, and uh, I'm sure I could have used many times before, and then Adam was like, Oh yeah, well, hold my beer, and he was like, selfie, selfie, selfie, you know, and uh and then somehow had the right answer.

SPEAKER_03

Uh okay. Okay, so so here's the thing.

Adam

Um, it just came out right. I hadn't planned it, it's just developing. But so this one you understand, this is sort of a classify thing, right? Because really, the dyadic iota, right? The index of has a built-in unique that we don't think about, but it's important here because what's actually happening is it only looks for the first position of any one element, so there's actually unique here, right? It's the only thing that's not this would give the same result if it's unique, but if we had like an F at the end, so we can't get rid of these, but they're not considered, nothing will ever give indices, there's nothing we put over here that will give indices four, five, six, right?

Conor

I guess I the problem is I never use dyadic iota, I don't think for like anything. So I I don't even okay. And like in my mind, suboptimally, but like I just don't reach for dyadic iota. Uh okay.

Adam

Well, I mean, we look we've we have real customers like at doing things, and APL has this huge toolbox of amazing things you can do, but I would say most applications out there they just look for information and retrieve information, don't like and then do a little bit with it. And looking for information, that's diet. Retrieving information, that's indexing. That's that's like 90% of what business applications do, looking things up and extracting it.

Conor

Well, what is uh what is tiny apple because did tiny apple borrow um they borrowed the membership? Uh well I guess I can well I don't wanna but anyways, yeah.

Adam

Anyway, let's let's let's go through this. I'll explain it. Okay, so index off it returns the first index off. Like it even exists in like JavaScript, there's an index off. That's dietic author, right? Uh sorry, say again. Say index off even exists in like JavaScript. And it's the same basically definition. The only difference is what if it's not found, but that doesn't matter here.

Conor

Well, so I think the problem is that maybe that's this is what I'm thinking. Uh, because tiny apple has both index of and uh this one's called element of. And if those are the same thing and tiny apple has borrowed no, that's not the same thing.

Adam

Element of is is is this, right? Oh, sorry. Right? That's if it's a member.

Conor

Uh did you just type that, but it's not a member, it's not in uh dialogue APL membership? No, it's using uh new font. Okay, so this is no, so I okay. I'm not uh I was just trying to maybe think that like maybe I use it all the time but in a different language. But yeah, for whatever reason, I just don't use Diata Coyota. I don't know, I don't know why what I'm what I'm doing in the cases where you need it, but anyways, continue.

Adam

We need to look up the position of something, right? So we're looking up the position of everything itself. So that's essentially has like a sort of a uh a nerfed unique inside because we only consider the the first time an element appears. So all the a's get mapped to position one that is there, right? So this so automatically this gives us the first position. I'm I'm using this property that I that's diadegayota will give us the first location of any one element to get the first locations of all the elements. So this is all these numbers are the first occurrences of all the elements, right? Then I want I want a variation on on diadega yota. I want the one that gives me the last position, but that's not built into the language. Then I'm constructing that piecemeal. So how can I find that? Well, let's say we start by uh by reversing instead, right? So if we reverse, then we're looking up, think of this one as being reversed. So we're so this is position one, f, this is position two, this is position three, and so on. So a gets mapped to two, okay. F A, right? And b gets mapped position six because we're counting from the right. But we can't compare indices counting from the left with indices counting from the right. So how do you how do you swap which direction an index is counted from? You do that by subtracting them from the total length, and then you have an off by one error, but I'm not worried about that. So basically, position five from the end is position length minus five from the beginning. Are you with me? Yeah, okay, so that's exactly what I'm doing. So we'll take these numbers and we'll subtract them from the length. So we'll take the string again and subtract. Okay, this is the position from the beginning. So the f the last a is in position five, except we have an off by one error, but that doesn't matter. Position one, two, three, four, five. So yeah, off by one. But since it's consistent, I'm not worried about it at this point. Really, we want because of fence post, whatever, we want to add uh add one. These are zero indexed now. Okay, great. So we have the indices here. And we do uh actually it's the other way around, but it doesn't matter. So we're subtracting the last position, right? So sorry, we're subtracting the first position from the last position. That's why I'm commuting the the minus, and that gives us these numbers. And luckily, we needed to we're off by one, but we needed to subtract one anyway for the problem statement, so it all works out, just happens to be. And from here on, everything is like we did before, we just need the max value. So all good. Now, of course, this is longer than this. So I'll just show you how we how we get there. Okay, so everything notice that this works out very nicely as a train. Immediately we can see that because uh we've got a bunch of functions and all the arguments are the same, right? So if we try to first define this as a def and nothing, then it makes it easier to see. Right. So we'll let's let's just do that down here. We'll put the argument uh out over here and replace them with omega so we can because annotation is really important, and being able to just spot the patterns much easier if you have a symbol than if you have a whole uh distracting uh string. Okay, get rid of all those pesky spaces because they're also just distracting. Okay, so all good. This works. We can even try it with all our test cases. We do it on this one, we do it on the ABC one, and we do it on the one with like the all the JSON necklace, right? Shouldn't this give zero by the way?

SPEAKER_00

Uh no, no, I think that's right.

Adam

It's uh it's the still yeah, it's why there's one in between.

SPEAKER_03

Yeah, it's not AA, right? It's just uh yeah, we can do one more that's Rich with the save with the save there, Rich. I like that.

SPEAKER_01

I was also thinking the same thing.

Adam

I was like, oh yeah, yeah, because I changed the case one before it wasn't AA, right? Okay, so now we go through this. So this one is a selfie, right? You should you spot that. So this isn't a commute, this is actually a selfie. We'll do that. This is the length, we leave that for now, and this this pattern is exactly the new thing in version 20 of dialogue, right? We with the behind operator. Sigma combinator, and this favor. So we can type this like this, okay? So this is our next step. I should give the same thing, and at this point, we're basically ready to go to go test it because we we now have one, two, three functions that are uh applied to the argument. We have got intervening functions with them here, and then we got an atop with the last one, which just works out beautifully. So get rid of that one, get rid of this one, I'll get rid of the parentheses later. There we there we go. And now we get rid of the parentheses like that.

SPEAKER_00

Yeah. Max has a great suggestion. Can you uh inline trace?

Adam

I'm interested to see how uh whether this clarifies enough. So this is the new inline tracing in version 20. Uh, we can make this a bit bigger so we can see that there's this is the argument in array notation. And so we this is the function here, and it's being given this right argument. Uh we're now stepping into it, it's parsing through this basically, step by step of the train that's working so far. Stepping into this, which is just a derived function. Finally, we're going to remember it's it's behind. So first we apply the reverse on this argument, and then we can say now this one is being applied dyadically, so it opens the window over on the left. It's working beautifully so far. So now we're looking up the right direction array into its reverse, and uh then we are applying the um the length here, doing the subtraction, seven minus all these indices we computed before. Then we go find the selfie, we step into that, so we can see that's the same argument being applied twice with the right and left arguments of iota. That gives us all the selfie uh indices, and we subtract the uh um them from the indices we computed before, the last position ones. Uh we flip the arguments for the the commute, and then we have all the candidate numbers, and we take the greatest one and we can return. Uh not sure what this oh right now we're doing exactly the same thing on the second uh one because we do this in each, right? So we're stepping through it. I'm not going to actually go through the whole thing with with uh with all of them, but stepping in all the way, reverse, index of length, do the subtraction, the index selfie, and the subtract to get uh get all the candidates, and that's all negative ones. Okay, I'm just gonna step out of that. So I just think it was a great demonstration of using the inland tracing. Good call.

Conor

All right, there's a bunch of things I want to see.

Adam

Um how did this compare in length to the other solution?

Conor

Can you put uh this original solution? It's I guess I stored as F. Now this new solution, and then also the indice were because then there was the one. Wow, actually, which one?

Adam

There was the one just the one where we re-implemented key in terms of the outer product, right? There's no point that's what key is doing anyway.

Conor

Well, so I want to I want to do the compare X on a like random string of 26 lowercase or like maybe a thousand lowercase. We can do that.

Adam

Uh so this one, this one is F and this one is G. But we don't, I mean the outer product is going to be terrible.

Conor

That's alright.

Adam

We can do it if you want. That's okay. Should we do it? Nobody knows. I can't read which one do you want to do? The nested one or the the flat one?

Conor

Let's do them both. Let's do them both. Let's have fun. Let's go wild, let's go crazy. And so while while Adam is putting this together, compare X, or um maybe there's there's like four different ways to spell it runtime, etc. etc. Is this beautiful thing that is in the dialogue APL REPL? Uh or I guess this isn't the REPL, this is the IDE or whatever you call it. But the you can basically inline profile things with like little Unicode boxes, and it's always a fun activity when you have multiple solutions to uh different problems uh to see which one is gonna be the best one.

SPEAKER_00

And I guess uh oh sorry, a couple uh comments send the role. I mean, yeah, it's a diadic iota is exactly oh, index in is what they call it in Wear, is that right? We call it index of, and then JavaScript has index of. Uh, but yes, that sounds like the same thing. Tubo. I want to add inline tracing to my own Lang, to my own language. How much would you say that the language design enables disables this? I mean it's just about whether you can pass things at runtime, isn't it? In order to have inline tracing.

Conor

And also just uh FYI. Uh C4 Tubo is actually, I believe, I'm gonna kill myself if I get his name wrong. Chris from uh the Progue Lang Cast uh and Proguang Base YouTube channel and podcast. Oh, for real. Which we interviewed, right? On Eric Raycast? I'm almost positive we did. Christopher. Okay, got it. So you know you're getting old when you're like, uh, is my memory gonna work in this instance? Um and and the YouTube channel or YouTube channel, YouTube channel, podcast, all the same thing, I guess. They interviewed um Marshall one time, which was a great interview. Uh so, anyways, go check out the past uh Progline cast and ray cast episodes. Um and right here we got now uh Madeline Brigani, uh Tiny Apple. I was saying earlier in the podcast, I'm not sure if if you just joined live at this moment, Madeline, or you were listening at 2.0 XP to catch up. Um but I was I was wondering if Tiny Apple had Classify because I couldn't find it, but maybe it existed under a different name. Um but then also too, classify gives you that gives you the different indices, and actually, is that what you want? Because the different solutions we've looked at are you know you end up with the matrix or the the nested array, which then you can do your indices or your you know min-max forks on. But if you have classify where they're all jumbled together, can you actually do anything with that without you know having to split them up into the nested array that we got, anyways?

Adam

Um so so I have a question for you, Connor. I can start doing the timings now, but the data is a bit interesting. If I just do random letters from the alphabet, we're going to have very few duplicates. That's also a question of how big should we make at least?

Conor

Make it a thousand, uh make it just a thousand character string. That's all I want.

Adam

One one thousand character string?

Conor

Just one one thousand string.

SPEAKER_03

Yeah, yeah, yeah. Okay. And then we want to do uh F G H and I. Can we see the string? Let's see the string. Show us the string. Show me the string. You want me to scroll? Yeah, it's pretty good. I mean, and you know, everyone, everyone always says, Oh, blah, blah, blah. You gotta show all these. Have you got the the deaths out in a in a row? Um, I don't think I don't remember if it will show.

Adam

Is that all varying? Never mind D there, we can erase that. I have no idea.

SPEAKER_00

And also the the shin might not be accurate. Good thing you didn't have any. It is.

Adam

It's not the only time it fails. Yeah, the only time it fails is uh is if you've got things that have to be parenthesized, but it doesn't seem like it.

SPEAKER_00

But our intuition is h and this one.

Conor

Wait, wait, before we do the intuition, so just just as a recap, we've got four functions here. They're called fgh and i. Not that that matters. F corresponds to the key solution that we showed right off the tap. Very beautiful, right off the tap, right off the top. That's the problem with live streaming, folks. Your speakos end up in the final cut. Then we've got G, which is the well, I guess we lost a selfie along the way. It was the selfie, selfie, selfie. You know, we're using the sigma combinator uh that we walked.

Adam

We don't need it for this one because behind, right? So it really there should be one here, right? Because this it is essentially the self um index off with a with this behind text on. But the selfie is implied when it's monetic, so there's no need to do it. That's why I removed it here. Does that make any sense? Okay, because we can just if we don't have a left argument, we just use the right argument on the left, so that's it doesn't make a difference.

Conor

But it was to show the relationship between formerly triple selfie, uh now double selfie, and then H and I are using the same uh min-max fork idiom, but one of them is using the uh unique outer product to get the indices corresponding to equal characters on each row. Uh, but then we learned the beautiful unique equals enclose fork, and the majority of those solutions are are the same. The interesting thing is after we uh profile this will be to is it gonna make a difference if we go in and uh replace some of the uh min's with firsts? But first, let's just uh compare is it running? Oh, look at that.

SPEAKER_03

Folks, we saw the intuition.

Adam

Another thing I I changed a little bit uh uh analyzing the thing before, but uh I I ungulfed a little bit uh because of the it's more efficient to do the max first and then subtract one, then subtract one from a whole bunch of numbers and then do the max. So I changed that a little bit as you were talking.

Conor

That's fine.

Adam

But it doesn't make a huge difference.

Conor

Well, so I mean the the listener, I mean we could we this doesn't looks wrong. We can still do the intuition, even though now we've run the expression. Um what were you gonna say, Rich? Just blind. I'm just I'm just covering up the in my own view. I'm just covering up for the audio listener. He's got a hand over the bottom half of his monitor.

SPEAKER_00

Oh, where the where results are. But it doesn't matter because it it sort of matches what I thought, except for Adam had already, if you were listening earlier, given the game away about F and G. The obvious big difference is between That's a lie, actually. I mean, it's slightly surprising. So H and I expect it to be a lot worse because they're both doing uh essentially out-of-products out-of-product comparisons between the entire individuals.

Adam

Remember, it's not it's not uh n squared. We the unique is very small. Yes, there are a thousand elements, but we're only comparing them to 26 of them, right? So it doesn't matter as much. And the same thing goes for the difference between nested and flat in this case, very little, because there are only 26 elements. So it would be it would be much more interesting to have many many more different elements that it could be. I mean, we can do that. We can just do it with numbers.

Conor

I think you want to add digits and uh uppercase random other. Just use numbers. Oh, yeah, just use numbers, yeah.

SPEAKER_00

Uh what am I doing here?

Conor

Yeah, and then well, actually, first before you do uh a bunch of numbers, just do 0 to 25 or 1 to 26 to see if we get the same because you never know strings versus integer arrays. Yeah, no, we do know.

Adam

We do if then yeah, because then the characters and and small numbers are stored identically internally. So yes, we do know.

SPEAKER_03

Show me and I will believe you.

Conor

I I've I I've as a former C compiler compiler. Okay, so here instead of indexing. I trust nothing uh performance result-wise until I see it. Uh, because there's so many times where I've been like, well, obviously it does this, and uh you know compiling is so we can do this and and for uh so we I'm not sure if we actually fully it's like one bit difference in the internal representation between the numbers and the thing.

SPEAKER_03

Whoa! Look at that.

Conor

Who was correct? Me. One second. No, no, no, did I make a mistake here? Maybe. So wait, and also why Adam is potentially fixing this, in case it wasn't clear for the audio listener, because we did some intuition, but then I'm not sure if we fully recapped. For the character string of uppercase letters, the slowest by a factor of two compared to the next uh actually, I guess we should do it as compared to the fastest. It looks like it's about five times, six, seven times slower. So it's the slowest one was the key. Then the outer products, um, the outer product and the uh kind of idiom that is similar to that, the unique equals enclose, uh, are very close, but the outer product is slightly faster, and that's about half the speed of the key. And then the fastest by far was the double selfie using the dyadic iotas. And now Adam is trying to fix the integer to match.

Adam

Is that function that that uh Rich was warning about uh the diffs that this removes too many parentheses? It effectively removes too many, despite my thinking it was good enough. And we can see here that if you compare these two, I'll run this one again for the so yeah.

Conor

This one uh I guess the noise between the outer product and the unique closed these these two have to compose compare.

Adam

This is the numeric one, this is the text one, right? They are virtually identical.

Conor

Okay, yeah. So that's just to say that the noise between the the last two solutions, H and I, that were the outer product uh unique and then you the unique equal enclosed, those are effectively you can count as the same because there's between the solutions one time, one was faster, the other one time, the other was slightly faster, and one of them they look identical. Uh so the point being is key is by far the slowest by like a factor of six, and the h and i, the outer product, and the equivalent uh you know, fork unique. What do we call that in idiom? We I guess we just call it unique equal enclose. Those are about three times as slow, and then the fastest by far is the diadic iota, which why is key so valuable?

SPEAKER_00

Because key in this case, we're giving it a uh oh a custom operand. Oh, that's a good point. If you rewrote this so that instead of a custom operand to key, you just did enclose omega. So you basically just rephrase key to become what uh it seems uh in BQN is in uh group, sorry, yeah, just group, group indices slash group. So we want to do and it's been argued that this is a way to do it. So like a little under the covers here is the the sort of rationale behind some operators, uh at least in dialogue is what you can do is because you know you can inspect the operands at runtime to see what the functions are actually spelled like. And by doing that, you can take some of those operands that you expect users to use and optimize them as special cases, right? And that only really works with operators. Um but of course it means you have to spell things in a particular way, unless you have something that's something like just in time compilation or something that can track, you know, there's this there's this idea that floats around called thunks, which is uh keeping track of things that have not yet been computed or that you intend to compute, and then passing that information along to future functions, and then they can look and say, Oh, you said you were going to compute this, but actually, since I'm gonna compute this other thing and I know what you were gonna give me, we can actually do this other thing that's faster instead of it uh materializing intermediate values. Anyway, that's the rationale, but in practice, you know, it's hard to anticipate, it's hard to uh produce all of those special cases. But one of the special cases for key, for example, in stencil is like this too, is just group the stuff and give it back to me as a nested array. And that is so fast with the special case that sometimes it's a lot faster to do the grouping and then apply your operand function with each instead of applying the operand function directly.

Adam

So now I don't know this must have been a dialogue. Something yeah, something happened over here that uh that made it run slow. Here it is again. We can recognize this pattern from before, but now the key one is much faster. It's faster than the outer product ones.

SPEAKER_00

Right, which is what I would have expected.

Adam

Yeah, so the only thing I did was you made here. So if you compare F, uh that we have uh next to each other. Yeah, I'm going to take the carry them down there. Cool. F there and F2 there. So firstly I switched to implicit, uh to explicit because too many. But uh basically what I did here was instead of feeding this giant custom operand to key, I'm just using this operand, which would be slow because it's the it forces nested arrays, but in fact, it is a a spelling that key recognizes, and instead of going through all these motions, it knows exactly what to do. Exactly, it's internally optimized, and so we go for go from there. Another thing that's interesting to look at is the instead of max, we want to do first and last, so we can try that as well.

SPEAKER_00

Yeah, if you do you could do right tack, you just switch something for the taxation from right and left and left. What do we call it?

SPEAKER_01

G G H H I I or whatever.

Adam

I guess uh it doesn't matter so much. We can just call them uh I just have to find them uh here. This is the F1, right? So this is F A. We wanna replace uh the last and the first. Okay, right like this. It doesn't matter if it's how we start. And we want to do G doesn't matter, it's the same thing, it's obviously going to be fast still. And I here we wanna do the last one and the last one and the first one and the first one. F G H and I like that. And then we want to do that.

SPEAKER_05

Do you expect these to be faster?

Adam

Yeah, a little bit at least. I'm not sure if it matters so much in the grand scheme of things, but uh but we can try it.

Conor

See, this is where this is where, you know, I have uh what do you call it? I guess I don't have a name for it, but like there's these optimizations that you can make. Well, I mean I guess I guess this stuff is built into interpreters like dialogue APL and BQN, but like the you know, I I've always said if you keep track of the sortedness of stuff, you know, like uh you can make optimizations, like if you ever call min or max on a sorted sequence, it'll just dispatch to like the first or last. But then people say, Oh, like when would you ever do that? This is an example of where you know having those kinds of because I know that like I'm I'm not sure if dialogue tracks it, but I know Marshall said that in BQN he has a bunch of these like metadata flags that track the sortedness and whether it's Boolean, etc. And then they dispatch to different algorithms. This would be a perfect example. Like if we saw no perf difference, you might be able to assume that uh because the uh indices of the result of these operations are always going to be sorted, if you're able to track that. It would um and as we're I mean, uh Madeline's been posting in the chat. Oh, here we go. Never mind. We'll talk about the tiny APL. Uh yeah, we'll come I'm gonna look at this.

Adam

Should I have sorted these?

Conor

Uh yeah, just can you do the defs under underneath this and then we can show it all on one screen?

Adam

It's sort of I can, but it remember the def doesn't show it really correctly, but it gives an idea what's what is supposed to happen because the it's missing parentheses around a bunch of them, but it doesn't matter so much.

SPEAKER_00

What's happened that's interesting? Oh yeah, okay.

Adam

We're trying to do the right we really want to compare F with FA, so that's nine percent faster there. Wanna comp F2 uh it didn't mat F2 with F. Oh, yeah, but mean optimization is no no, I messed it up. I'll I'll redefine that. I messed it up. That's F2, and we want to do an F2A is this one.

SPEAKER_00

I really should just compare two that are the same with rights and left instead of max and min's instead of trying to put them all on one. F2A, but what I was thinking as we should do is just sort these instead of makes it easier to do it.

Adam

So how did we do it? A top behind.

Conor

For the audio listener, the last of last index of double selfie solution is still the fastest, but looks there looks to be small improvements to uh replacing the min reduction with a first. And I guess technically I was gonna say, have you did you replace replace the max reduction with a right write reduce, which is optimal.

Adam

We can't do that. We can't do that here because you don't know which one is going to be the largest one. There we actually need the max. It's only the only the ones to find the indices, the first and last index, those are the ones that are that we can replace. Why do I have two F2s? Doesn't matter. But this shows us something about uh it shows something about the accuracy of the results.

SPEAKER_00

Because you wrote F2 twice.

Adam

Yeah, I wrote it twice for mistake. It doesn't matter, but that knows that we can we can't we actually everything is like plus minus five percent anyway. So f2a, we can see that it it didn't really make a difference from F2 to F2A. Um F A is significantly f faster than F. Uh G, it doesn't matter because it doesn't use that technique. You can see A, you can see these. The H A is slightly faster than H. IA is slightly faster than than I. So yeah, it does make a difference. F A versus F where it's the biggest difference. That's probably where it's that's probably no yeah. It's no, it's the same amount, it's the same sort of percentage-wise difference, isn't it? Out of the whole total work.

SPEAKER_00

But they're direct uh directly comparable because they're the literally the same except ones using rights and left, ones using max and mints. And so there's another thing it's interesting, yeah, why because the number of times it's running should be this the number of times it's running should be it's just the number of unique elements for both the key.

Adam

The way key is slowing everything down, yeah.

SPEAKER_00

I don't know.

Adam

Yeah, I'm not sure why there's it's the same relative difference. Everything maybe key is just slows everything down inside itself. So easy so the relative difference between max and mean is just gets exaggerated in there. I don't know.

SPEAKER_00

Maybe every time I don't know.

Adam

Oh, here's another thing. No, and here's another thing. Key might reparse its operand every time around the loop. But right tech reduction and left tech reduction are uh are tokenized as such. They're two cliff tokens actually.

SPEAKER_00

Oh right.

Adam

So it might it doesn't need to reparse them, it's not actually a reduction at all. It doesn't go through reduction code at all. It immediately goes to the last last major cell function and the and the first major cell function, which are primitives in the interpreter, but not in the language. So yeah, okay. But as you can also see, it doesn't matter if we're using numbers or characters. If we if you compare those those two here, it's exactly the same time.

SPEAKER_01

Do we wanna you at one point we were gonna change it to have way more? Way more possibilities, yeah.

Adam

So now we can do that, right? If we go up to well, we could just do it here. So if you do uh big n is a thousand, reshape one thousand instead. Right? So now there's there are much smaller chance of there being duplicates. There will be some big duplicates, right? So if you do G is the fastest one, right? So it's a very there are duplicates and they're far away from each other. Birthday problems abound here. Uh wanna run the unique on this as well. No, it doesn't matter because we need what do you do we want to run all of it on this big one as well? I guess so.

SPEAKER_00

Uh I guess I was thinking more just comparing like key and outer product, and so like just G I H or whatever we can pass it afterwards. Uh Madeline's index of solution by far the slowest.

Conor

We'll show this. I mean, you guys aren't gonna see this, uh, but I've I've been compiling Madeline's solutions. I mean, if you look at the YouTube stream, it'll show up in a couple seconds for you. Uh or now. But Madeline has a couple different solutions. We'll look at this in a second. She's mentioned that her index of is the slowest, but that's just an implementation thing. But anyways, the solutions are back, folks.

Adam

And now there's a big difference between some of them. No, because they're in different order as well, so it can't really start to compare. Uh so now there are many more. We can count the unique, right? Telly unique N. So there's six four unique values. That means there are very few, very few duplicates, right?

Conor

And so just yeah, once again, because we've been uh you know, we're watching this on screen, so we don't have as much confusion as as I'm sure the audio listener does. Definitely have to go watch this on YouTube because honestly, this is uh this is a valuable educational material, folks. I'm learning a ton, and it's probably way easier to follow along if you're watching the video. However, if you really do like the podcast format, what we're doing now is we switched from our 26 uh possible characters in a lowercase or uppercase string to now uh an integer sequence of up to um anywhere to a maximum of a thousand possible values. And so in this test sequence, we have a thousand characters, and we just did a tally of the unique, and so there are six hundred and thirty-four, much higher than the possible 26 unique characters. And now we are going to see the impact on the profiling of the same solutions that we just looked at for the character string. See, my guess is what is I was gonna say he's looking for the maximum.

SPEAKER_03

I was gonna say it's either a thousand or he's looking at what's the most occurring thing.

Adam

So the one that has the most duplicates has five duplicates, right? Interesting. So so this is a whole different it's a different set that we had before, and they're they're two-byte integers. Not that it matters a whole lot, but yeah, you can go looking for 64-bit floats if you want.

Conor

So the trend is the same, it's just more exaggerated, where we we have a solution that was six to seven times faster, the index of compared to the slowest one.

Adam

F A and F are the ones that are really slow, the key solutions there. Uh the F2, where we broke out uh the post-processing of the of the result from key, uh, is it takes half the time basically as before? It helps a little bit to do first and last, as before. Here, the this is plus minus five percent. So so by now everything is drowning out, and we yes, this is five percent faster with the first last. The fact that this one is slower than its first last one, I I wouldn't take that at face value. I would re-measure that if it was uh because I don't believe it. I mean C MPX, we just try it. C MPX, uh H big N and uh H A big N. I think it's just noise and uh and drowning because of the other things that are going on. There you go. Yeah, that's expected. So yeah, first last is better. This, I mean, I also get something out of this. This we this is helps me in in bolstering my view that we should add the last primitive. I think that would be like even conceptually nice things to have. So we could do like last minus first. That's one thing.

Conor

Oh, because uh because people don't necessarily reach for the right tack reduce idiom. It's more of yeah, I think that's it's more obscure, right?

Adam

And it's not the same either. Right tech reduces is last major cell. This would be last element in rebel order. It's not the same. It's last like it's not even last major last column or well, it's it's last really should be like this. This is last major cell. Last yeah, oh yeah, that's true.

SPEAKER_00

Sorry, yeah, it is last major cell there.

Adam

Right? So how you want to write it, yeah. And this is first major cell. All right, and then we've got first column if you're right tag slash bar, left tack slash bar. And yes, sorry, I should speak this up so the listeners. And and yeah, and and left tech reduce, right tech normal, like last axis reduces, those are left and right columns in a matrix and not very meaningful in the higher dimensional array. And then we've got a first function that this as a disclosure one, right? It picks out the first element or coerces one out. That's another difference that you you can't do last element with a right tech reduction over an empty list. But you can ask, or you can't do the first one either, but you can get the first element which coerces out a prototype. So, how do you get the last one? So there actually is an a built-in idiom thing where if you it this tokenizes, but there's not always the combination and ends up nicely, you might need like in the top. So there's a a first of the reverse, which is also seem to be slow, but isn't if you're lucky. I think it would be nice to have a reverse, uh a last glyph, is something quite often, especially in this case, it was actually first and last. But I find that it's very often I want to operate on something that has exactly two elements, and I want to be able to address the left element and the right element, and that's also first and last. Um, so that's something I want. So that's one one thing that this has done for me. Another thing has done for me is this exact thing of key with the enclosed right argument, that means key that just works under on the indices and returns a list of indices, list of lists of indices, um, is an extension to key that that's key with vocabulary essentially. This is just a group by function. Sure, but key with vocabulary does accept that the my proposal for key with vocabulary.

SPEAKER_00

Oh, would do that as a monastery as well, right?

Adam

Yeah. If no, you have to provide the vocabulary as yeah, but we in this case with the alphabet, we know what the vocabulary is. Sorry. Yeah. So if it al if sorry, so if we were to write how would you spell it?

SPEAKER_00

So right now it's doing open curly brace enclose omega right curly brace key, and that is the group by function returns a nested list, nested vector of your uh uh so with the vocabulary, it wouldn't yeah. Um what's called uh let's see if I can find those. Adam has a proposal. Well the key in dialogue at least, the one of the bugbears is that if you want to uh sort your results or if you want to have sort of um fill you want to have results that include uh zeros, for example, where an element an element type that you know about doesn't occur, yeah. Then you have to prov you have to prepend basically your onto your argument and sometimes onto your set of keys, a vocabulary, a set of you have to basically prepend with the unique elements that you're interested in in the order that you're interested in.

Adam

Yeah, so if we do this, right, if you let's say we want to find letter frequencies, so here we can. So this this is not a useful result because we don't know what what they are, right? And even if we even if we do put in the left argument here, so we do like this, this doesn't give us the zero for all the letters that are missing, right? How many X's are there? We don't know. It doesn't say. We have to fill that in later. So that's uh that's a bit annoying. So the key with vocabulary, which of course it can do the same thing, but we can basically tell it. So if you go back to just this here, we tell it instead that the vocabulary is the alphabet. And now it gives us even the letters that are missing. And then we can go and and check for each one. So this is again this pattern of wanting actually wanting this and actually wanting for all of them, in our case it wouldn't it wouldn't matter because first and last it wouldn't have made a difference anyway.

SPEAKER_00

Oh we explicitly only care about the argument for the for the per weekly challenge.

Adam

Sure, but but here's another problem then. So let's let's just say that we did have key with the vocabulary, and now we want to do the first and last. So we get we get these lists here, and one of the lists is uh the empty vector, and now we want to do the uh well, the last minus the first, and we get an error, like we said before, because they're not the same. Really, what we what we want to do is we want to get the first, which we can get, which is zero, and the last, which is zero, and subtract them from each other, which is zero, right? And then it's all good, but we're missing the last primitive. So um let's get that.

Conor

Also, too, I I totally forgot that uh what was it? Let's go get the username. Was it uh D Zen Neroli? We said that we would mention the uh week if if uh they found the number, and they did. And then we were steeped in the solution. It would did we say it? Was it 372? Or did you say it, Rich? It is 372, whether or not it was said. Oh, yeah, yeah. So we might have failed. What are we at? We're at the like you know uh 80-minute mark. And so we might have failed to mention that this is. I mean, does it actually matter? Not really, but uh for folks in the future um that are 80 minutes into this, being like, wow, where's the problem statement? And potentially too, this is kind of a classic uh interview e. I bet if I search this uh on Google, it also corresponds to like a leak code problem. Um anyways, back to you, Adam. Sorry.

Adam

No, that's fine. I'm just I'm just showing how the key that always does uses that function but with vocabulary, it would still work because we'd get uh we'd get these distances being zero here.

SPEAKER_00

Yeah, but then you get a bunch of negative ones for things you don't care about or it doesn't matter because we want the maximum, right?

Adam

Oh, you're right, yeah. And then and then subtract one, so sure it actually doesn't matter. Well.

Conor

And it is indeed lead code problem 1624 with a much more specific name of largest substring between two equal characters. So I was thinking about this because what am I going to call this episode? Should I call this episode like key versus index of versus outer product? Because honestly, that is what's more I think important here. Is like we're discussing the trade-offs between primitives, how it affects your solution, uh, or do I call it like PwC, you know, 372 part two, which means absolutely nothing to like people of the interwebs, but like will mean like when I think about this uh episode in the past, like I will think about, oh yeah, that's the time we solved that pro-weekly challenge problem. Like, so uh you know, it's uh what should we actually call this? Because currently this episode does not have a title. Uh the you know, repeat listeners will know that uh we just called it 125 and we're gonna we're gonna add a title later.

Adam

So yeah, it was a big problem for us at dialogue, by the way. And we our website people were unable to put this episode on our calendar of upcoming events because there's nothing to put in the title.

Conor

See they can't just put array cast 125. That's not uh that's not enough information.

Adam

Uh I guess not. That's a value or something. Choose in advance when you're not interested. Um so so yeah, I think I think this is pretty neat. Um I I I would think that key with vocabulary can be made faster. My model isn't intended to be fast in any way, but I would think it could be faster because key, when it starts working, normal key, it doesn't know like uh like for with this function of in-close omega, it doesn't know how many unique elements there are. Right? It will have to traverse first and find out what are all the unique elements, or as it goes along, it will have to make more and more uh result collection pockets where it's going to keep adding in in indices, but it doesn't know how many they're going to be, so it doesn't know how much space to reserve for each one of them either. I would think that it would be advantageous for key to know in advance that I'm only looking for these 26 letters. That means if I find any elements that are not among these 26 letters, I'm not going to consider them. Just going to skip them. So it knows it can start building up slots of uh 26 slots.

SPEAKER_00

It doesn't know how many it's gonna find, so I don't think that's true, but now it has some bound on them.

Adam

It knows they're going to be a great many duplicates, so it could at least on average, or some kind of uh I don't know, geometric average thing. You could it could start off by reserving like at uh twice the or something like that, the the total number of elements divided by the number of elements we're looking for, something like because it knows it's going to fill at least quite a few of them. Then it can always compact it later. Something like I mean I don't know, I'm not a supercommer. I think I think some things could there's some tricks they could do sort of uh guess to best guess and compact things later rather than having to be completely in line to what's going to be later.

SPEAKER_00

Indeed.

Adam

Um and you could um if this works in the model actually.

SPEAKER_00

Connor, as we surpassed minute 83 or so. You had the collection of uh Madeline's tiny.

SPEAKER_01

Yeah, should we show we should we show those uh the solutions? You want me to stop sharing? You can show those?

Conor

Yeah, I'll uh I'll steal how do we do the entire screen Google NeWorks. It's a little behind the scenes for the YouTube people because they can see for like three seconds my uh monitor, my multiple monitors. Uh show my screen, anyways. There we go. And so now I'm gonna be staring at my top monitor, even though you know You want to click that button. What button? Oh yeah, yeah, yeah. So you're behind now, but uh if you it depends on whether you're watching the YouTube. So what page is this as well? Is this the array box? My uh my array box is array. Is this the array box that's up? Yeah, and it's beautiful, folks. I mean I tweeted the other day that you know the AI hack is I now have like vibe I've gotten the AI to program me GitHub actions that like monitor when there's ever updates to WiWAM, J. And then whenever it notices an update, it automatically kicks up another GitHub action that goes and like pulls down the source, compiles it, gets the WASM executable. So now every once in a while I just get a pull request on this repo that says, hey, we got you the new version. I just click merge. It's beautiful. Everyone else was upset. They're like, oh, you've exposed yourself to supply J attacks. Listen, folks, if I get a supply chain attack, we're doing great. That means that people care enough about this website that they want to like, you know, uproot uh what I'm doing here. So we've got all the different languages. But you're only you're only try uh pulling from trusted people, right? Exactly. All the array programs you know personally.

SPEAKER_00

Corrupt one of the array lines.

Conor

People are just so anti-AI that like they're like, oh, you know, that doesn't work. And it's like, I used to do this manually and it was it was so just like laborious, and now it's so pleasant. I just like I wake up in the morning, I'm so excited to go to my computer, I'm like, ooh.

SPEAKER_00

You heard that first, folks. Here, if you can put in a supply chain attack that puts some funny message on arraybox.com, Connor will give you a prize. Hey, I did that first.

SPEAKER_03

Madeline, uh yeah, that's true. That was before you were one of my went live and then was like, here, kinda trust AI too much. You know the sentence scene. I gave it to Madeline recently.

Conor

Yeah, Madeline saying in the chat, you shouldn't trust me, and it's like, all right, well, that's my own fault. If you want to take down a RayBox with a uh you know, malicious release of Tiny Apple, it serves me right. But I was giving a uh uh talk recently at NDC Toronto just like a week and a half ago, and I used Tiny Apple uh for all of the code and like live coded the entire talk. And the reason that I used Tiny Apple is one, it has all the primitives. You know, when you look at the keyboard, it's just like holy smokes, we got everything, folks. Uh, and that's fantastic. In fact, I was thinking as soon as I was solving this in my head at the beginning, I was immediately mapping like, uh, what languages have primitives that would be a little bit nicer? And I thought, oh yeah, J has decrement and increment, which is plus one, minus one. That'd be nice, except for the fact that they're actually two characters in J, so it doesn't save you anything compared to like a minus one or a plus one. And then I forgot until I saw Madeline's solutions that, oh, that's right, uh uh Tiny Apple pretty much has everything. And so if you uh look at what the double dash except in a single Unicode primitive, this is decrement. Uh so you can I don't actually know if this saves, probably does save one character. Um but anyways, I uh I was mentioning that the reason I used Tiny Apple was one because it has all the primitives. Like I would have typically used BQN, but BQN didn't have the partition functions, partition and partition and close. And so I needed those. And then when you think, why wouldn't you use dialogue APL? Because dialogue APL has those. However, if we quickly copy this and we go to uh dialogue APL, if you try to uh output multiple things, so if I do like what do we just do? I guess we can just type a thing and then we do four, five, six. Because of the safety mechanisms that I put in place, you can well, is it because of this? Usually, actually, this says that I can't uh do this, or or maybe this isn't because of, but anyways, I'm using the Safe3 dialogue thing. And I don't know if that's what prohibits this, but multiple uh uh outputs don't work, whereas Tiny Apple, I have no problem. Uh I need I I just it just struck me now.

Adam

I was uh I was at the BAA meeting, uh the Bridge APL Association at this bi-weekly meeting, and I was showing some old code that I converted from uh some APL 360 code, and I converted it to this MyServer thing that you can say interactive thing, and how I'd mangled the code so you can do things that sort of like session. And it just struck me now that maybe the safe code could do something like where it goes in and replaces all the quad get tokens, basically, uh dual tokens, with something that collects output. So it might not be able to show output in real time, but every when you run it, it will collect all the output and show you all the output you sped out on the way. I think I can do it.

Conor

Yeah, potentially. Um anyway, so look forward to uh NDC Toronto uh it was called Algorithms and Combinators. It was a beautiful talk, folks, and I had a live coded, or well, not live coded, I had a vibe-coded live poll that was running like a reverse cloud fair tunnel on my laptop, and it had this beautiful pie chart animations of showing what languages people were using. Only possible thanks to AI. Um, but let's stop talking about AI and start talking about these solutions. So this was Madeline. So Madeline, creator, if you're not familiar, of the Tinel Tiny Apple language that we're looking at right now. So this is the uh index of solution, LOF or last index of. This is the key solution, and this is the original solution. So, I mean, we can look the through these primitives. So this is the group, which I believe uh initially comes from Cap and BQN, or maybe BQN had it first, and Cap added it later. And I don't fully actually so like this is so let's remark on the nice things first. So um uh Tiny Apple has the uh first, um, although it's called uh last. Uh and this is the first. So we've got first and last primitives. It's using the um cap syntax for forks in this case. Uh, and then we have the you know, max reduce, we have the decrement function, which is quite nice. What happened to my oh yeah, there we go, decrement. And uh this I was a bit confused of at first, but I'm pretty sure backward is just another way for the flip or swap.

Adam

No, no, no, no, no. This is this is exactly what I was doing before. Look, this is the one that looks at the that's the the the classifier thing, right? We look for the first position in itself. So there's a backwards, it's basically a modifier, it's not a normal operator, it's special. I think it's use a lookup table and it modifies iota to behave from the back end, right? So so this is a variant, if you want. Really, it's just a spelling scheme.

SPEAKER_00

Iota of from the end.

Conor

Yeah. So it's basically it's basically uh a primitive that could be spelled with multiple primitives as uh under reverse, correct? No. Uh no, exactly.

Adam

Then I would have done that because you have to subtract from the it's it's position of the last, right? Oh, right, right. It's it's a different primitive. It's look for the last element. It's not the same thing as well.

Conor

That's incorrect. Yeah, yeah. I should have the two words the tally minus earlier. Yeah. And uh Madeline in the chat is saying Elias, the creator of uh cap, uh, and uh they added them at the same time for the group primitive. Um so very beautiful. I mean, we've got the banana brackets in order to get the train syntax. And so this is the only thing that so I mean this is the group primitive from BQN, but it's uh equal group uh iota tally, which I don't I don't fully um and you can see that I had it here because except this was a mistake putting this because I wanted to I don't have uh actually I can just go up. Yeah, yeah, keep it this way. And you can see that I had it here because I was trying to just evaluate this, and if you get rid of can you do it with I don't think you can do it without that. Actually, no, wait, wait, wait, I'm doing this incorrectly. Uh I want to do shift enter. So this uh, which is just the equal group iota tally of the string, gives us the indices of the you know, a, b, and c oh.

SPEAKER_00

Is there some kind of thing going on? It's using the elements as the key into the group. Is it something like that? Well, so like it's grouping the indices, that's why it's doing the iota tally. So it's giving you need to get the indices first.

Adam

This is just this is just a key, right?

SPEAKER_00

This is just yeah, but it's a key spelled of like five glyphs. Yeah, but the iota tally is the are the indices. Yes, iota tally exactly. That's what I'm saying to Connor, is the data you want to group is the indices, not the I think if you get rid of that, does it just group the characters? Uh or is there a write tech or something? Yeah.

Adam

Yeah.

SPEAKER_00

So instead of grouping the characters, you want to group the indices at which they occur, which is the one. What is the equal do?

Conor

I was gonna say I'm guessing that this has to be a binary operation that's passed to group. No.

SPEAKER_00

Well, they know because you've got the wrong domain there, you can't less than characters, but you might be on to something. Well, what is equal? Monetic equal. Madeline in the comments explain.

SPEAKER_03

Although, why is it blue? Oh, it's classifying. Oh, okay, okay, okay. It's classified. That's fine.

Conor

So it's my docs have failed. My docs have failed.

Adam

Yeah. No, because it's um Madeline forgot to cla document it. Uh-huh.

Conor

Well, we can't blame Madeline yet because my guess is that it is documented and my scraping script missed it. Uh, I would I would trace try I trust the AI vibe coded uh doc scraper. Although never mind, it was it was Madeline's fault. She says, Oh, I did forget to document it. So this is if we go to uh BQN quickly um and we delete this, this is the and I can never remember how to spell this. I gotta is it this one? Is it this one? Is it this one?

SPEAKER_00

There we go. That one with is your cla is your group. No classify.

Conor

There we go. So this is the idiom in this is classify, I think, right? So if we do F1 classify, and yeah, this is group. Uh so and this is an idiom that I um am very familiar with in BQN because it comes up a ton. So in uh Tiny Apple, it looks uh like it. I guess it would look like this in the case where you were grouping the own stuff, but in this case you actually want the fork where Iota tally is uh the right tyne. Um so yeah, this is a fork that is yeah, doing classify group on the indices. Which is, I mean, the uh we haven't said this for the audio listener, but this is definitely the most verbose solution. Then the key shaves off four characters or five, and the index of shaves off one more. Um although Madeline did mention that the index of for her uh Tiny Apple is actually much slower, but that's not because I don't think it couldn't be faster, it's just the implementation currently. Are there any other things worth remarking on in so I mean it's it's very love, this is why I love Tiny Apple though, because it's got you know the it's got the last, it's got the first, it's got all the primitives, and so whenever like it always makes me so sad when you go to BQN and you need you or you want like the decode and the encode, or you want the partition primitives. Um and uh for playing around, Tiny Apple it's always very nice because and that's the thing is I I wasn't even aware of this backward. Um but you can like maximally play around with the different algorithmic solutions for this. And uh I guess I should delete this at the point.

SPEAKER_00

And it makes me want to find the docs for backwards. There it is. So I mean I can't show other things that can do that.

SPEAKER_01

Oh, it doesn't say if I look at the full full docs.

SPEAKER_00

Backward doesn't tell you what things can go backwards, but the things that can go backwards oh also don't tell you because it was for because Madeline forgot to document it. Yeah, okay, fair enough.

Adam

I just realized that I an optimization that I well, whatever. I weigh it's a nicer spelling of things, I think.

Conor

And I guess this is the problem with not having a full panel, because there was a J solution at one point that didn't use key.

Adam

I have a J solution.

Conor

I have it to present. You want me to present?

Adam

Yeah, yeah, yeah, sure.

Conor

Steal it away from me. Um it irritates me because this YouTube recording, it's I'm staring up at my ceiling basically. So it's it's nicer if uh someone else's uh screen share.

Adam

I'm not a J programmer, so I don't know what I'm doing here, but uh this seemed to work, and I just realized something.

Conor

Oh, look at that.

SPEAKER_03

We're in Juno, folks.

Adam

Look at that dovetailing from episode 124 with uh Juno. Uh so so this so this is the index of this is index of selfie, and this is index of last, which is a primitive in J selfie. So this is super easy. So subtract those from each other. Maybe I should tokenize this for you because I can I can't read J like this. Sorry. I mean it has different colors and it's all nice here, but uh seriously I can't. Uh okay, so index of last selfie, uh minus index of first selfie, maximum nothing over here. This is the cap uh thing, and then subtract one. So this is this is a solution.

SPEAKER_00

And I just realized together, you can put the slash next to the max. What? Right? Is that right? Right. Uh is yeah, that's one thing. Yeah, I mean if you want, but this is the thing.

Adam

Yeah. I just realized a couple of things, a couple of things that are nice here. One is I believe, and we can apply this to the APL, we can go back and do the APL afterwards, is we can break out the selfie over here, I believe. Uh like that. That still works because it's just a now it's just indexed off the left argument, which is so it's not as so that's nice. And this, I believe we can make this an inner product. But the inner product is not spelled any better in J, really, because you have to do like this, I think, to do inner product, but it gets rid of the can. Yeah, in J you do, but not in the okay, fair enough. Um and then so this is this is the whole solution. We can get rid of the spaces now. We can almost read it. Max dot minus can't remove this space, I believe, because then it's dot slash, which means something completely different. Uh but this is pretty nice, isn't it?

SPEAKER_00

Minus one plus the slightly shorter max dot minus index of the first.

Conor

Can't you do a decrement? Or is that gonna be longer?

Adam

Oh yeah, we can do a decrement, but it doesn't help because that would need a cap. Right. Because because you can't do a tops like this.

Conor

So it doesn't really that's the worst part of J, folks. I say it because Henry's not here, but uh the the two train being the S combinator, frankly, big mistake.

SPEAKER_00

is key in J.

Adam

Yeah, so we can use key. Yeah, but it's not not just slash dot. I think there's two keys because they realized that the dialogue key was so nice that they wanted that too. So there's so this is the key, and then there's like well that was Roger's fault, was it? Uh he brought uh J stuff into the key diet, yeah. This one. But anyway, so yeah, you can use it with the key. I'm not really sure how that works. We can try it if you want, but I'm not I mean scary stuff. Unknown territory here for AP. AKLE killers. I think we like like enclosed uh that did not work. Oh right, because we want I'm not doing I don't even know. That's right. Yeah. No, no, it's not because this doesn't give us the the indices.

SPEAKER_00

No, no, you have to provide the indices. So it's in an I dot. Like a hook or something.

Adam

Uh we have to do like or uh compose i dot compose with the tally. Yeah. Just like this or something like that, right? Yeah, so these are the indices. And then we want to group by indices. So we want to group like oh, I think now we can use the copy thing. Uh oh, it's probably it's probably the wrong argument order.

SPEAKER_00

Imagine is does J have a regex engine inbuilt?

Adam

It looks it looks the same. I don't know how to use the key here correctly on the indices. We want to we want to group the indices, but how do we supply what the keys are?

SPEAKER_01

If there's a J uh programmer uh in the chat.

SPEAKER_00

I mean there was one earlier, but um Have they explored the approach to only use the index of first and index of the element in the vector. I'd fill up the dot after slash uh for key.

Adam

Okay, yeah, so these are all the indices, right? And so instead of the this is the enclose. So I think marble we'll come back to what marble command is. Okay so here inside here we want well, okay. It does the parenthesis thing for me. We want to do the first and the last. Is there there's a head and tail? Yeah, it's uh brace colon and brace dot. Open brace and yeah, open brace dot. Uh this. Uh it's actually the last one we want, right? Last minus first.

Conor

Yeah, I can never remember which is which, but you know, you just you just switched. There we go. You try both and one of them will work.

Adam

Exactly. There you go. So now we we now we got this far, and now we just want to do the minimum on this. Right. So the minimum is X less than dot, but we can't we have to cap it. No, that's not right. We don't want to do the minimum, we want to do the maximum minimum. And then we want to do we want to um subtract one from this. So negative one plus, or we can decrement, which doesn't help anything. Just more caps. We could technically speaking glue it together with decrement over here, with decrement minus dot or something. I don't know. Uh decrement is wait, hold on. Uh less of that. Decrement. Less than colon. Of course it is.

Conor

Of course it is.

Adam

Uh and that was not right anymore. I don't know. I can't read this stuff.

SPEAKER_00

I mean we got the we get the impression. Oh, we got the the bulk of the colons because they got like the combinator.

Adam

Yeah, it's got extra colons for good order.

Conor

See if you're on a ray box, you could have just gone control space and typed in decrement. You never need to memorize anything anymore.

SPEAKER_03

Okay, thank you.

SPEAKER_00

That's uh is that true? I'm going on a ray box now.

Adam

Yeah, well, I'll steal it back to the box. This was interesting, right? Because this means that in J, this solution was so much better, the one like so much nicer as well. Actually read that. Now I'm gonna I want to go back to APL for a moment because if you look at um this in G, we could actually well it doesn't actually matter because this is the this is the last index.

SPEAKER_00

Sorry, and I'm gonna by the way, I'm working on a new keyboard solution for dialog APL, and I'm gonna steal APL space as a default shortcut for a keyword search.

Conor

It's control space.

SPEAKER_00

Well, it's depends what you want. Uh your maybe it will just be settable to whatever you want. Yeah, yeah.

Conor

And I I wasn't the one that came up with it. It's it's on, I think CAP has a version of it. There, you know, I everything on Array Box is just an amalgamation of all the best things across every single REPL in all the different array languages.

Adam

For sure. So so just what I what I thought of here is an APL is sort of nice to do an inner product here. I don't know if you like that. It's just it's not shorter. It's just because it's a reduction over mixed effective, like you could do it. It would be nice if if we had like a yOTA dot whatever, like an index of last.

Conor

Um all right, can I steal it back to show marble comas? Yeah, good technically credits. Uh I'm gonna pronounce this wrong, but I'll do my best. Adrax uh has a optimal Wiwa solution. And seeing as we we don't have the J representative, we don't have the Wi WA representative, we're just doing our best to showcase all the different uh array languages. So if we come here and um so yeah, this just to you know highlight on screen what I was mentioning, if you're in J or whatever you wiwa and you don't know how to type it, I mean in wiwa, you can just you know type the name of it. So you don't really need this, but uh you you know you can do stuff and and find it, which a lot of the times there's a subset in J and in BQN and definitely in Tiny Apple that I do not know how to type. Um anyway, so this is the optimal from by way of marble coma or or by from Adorax by way of marble coma in the YouTube chat. So this is the benefit of doing this on YouTube is uh we can fill in our lack of expertise in the array languages that we're not good at and uh borrow them from them. So I believe this is classify in um WeWah, and then this is unselect, which actually I don't I don't have the log is classify, bro. So do they have it? So I don't have the name of this, but there's a bunch of idioms that I scraped from the Wiwa docs. Uh and they have names, I think, half the time. So unselected, or like I don't know what it corresponds to, but this is an idiom. Um what I can I not get rid of this. And then we have, I believe this is complement or not, as they call it. Plus, uh this is minimum, and then unselect this enumerate an array, right?

Adam

Oh, yeah, totally.

Conor

What am I doing? Yeah, let's just let's just get rid of this. Get rid of this. Unselect. I can just uh yeah, we would have been able to see this if I just evaluated this like this. So yeah, it's enumerate zip with index basically.

SPEAKER_03

In front because it's stack based, right?

Conor

It's stack based. Oh a lot of things are backwards, right? Like every every function including uh binary operations are are prefix and uh so something's no diode, it's stack based, right, right, right. And then if you do not, ooh, actually, that's interesting. The not of your indices is actually one minus. Is that right? Did I just do that correctly? One minus, yeah. And so because you have zero index, it's one zero, negative one, negative two, negative three, negative four.

SPEAKER_00

And if we Oh, and then you add those together then that is like subtracting the indices from the last from the indices from the first from the beginning, indices of the last from indices of the first.

Conor

Breaking my brain. No, no, I yeah, it's there. So classify totally makes sense. If you have the string ABC C V A, you get 012210, that's fine. Unselect zips with the indices, then you take the complement or not of the indices, and that's effectively programmed as one minus, which uh Yeah, that's that comes from BQN.

Adam

It was because of fuzzy logic, that the the pro the probability of something not happening is one minus the probability of something happening. So that's why not is one minus.

Conor

But in this case, it you ri you end up your indices are transposed to or not transposed, transformed to one zero, negative one, negative two, negative three, negative four. And then when you add that transformed index sequence with your classify sequence, you end up for the case of ABC C B A 11102 negative four.

SPEAKER_00

No, you're right, I'm lost again.

Adam

Yeah, and then whether that makes sense.

SPEAKER_00

Uh or what it's for.

Conor

So it's and then and then so there is an absolute value at the end, which might make more sense if we do that. No, it's the distance. It's the distance to the uh actually wait, but you need it to be in front because they're doing a minimum here.

SPEAKER_00

This is if we go back to the plus, go back to the plus. I'm pretty sure that's the distance from this element. Can you stick another C on the end? Is that the distance? So that C is three characters away from the first C. And the A is four characters uh one, two, three, four. Yeah, four characters from the first A. And the B is two characters from the first B. But the first C is uh does that make sense? One, one, one, zero. I think C is zero characters from the previous C. Well, there are zero characters in between that and the previous C. And the second one, there are three characters between that C and the very first C.

Conor

Yeah, yeah, because the property of the classify, similar to what Adam was talking about earlier when we were doing the uh Dyadic Iota selfie, is that it's the first index. It's not just like the category, it's not just the label, it's the first index of it. And so if you do this, I mean it's still a little bit mind-bending that No, but that's it, right? That's giving you the Yeah. It's it's just a little bit mind-bending because the transform index sequence, it's not zero to negative six, it's one zero and then negative one to negative five. But when you add that to the classify, you get back basically a maybe off by one distance from the character to the first instance of that character. Yeah. Which happens to be exactly what we want. And then the the confusing part is that you have to go minimum and then absolute value. I mean minimum absolute value is just is it is it though?

Adam

Because uh just negate uh Madeline says you need to negate.

SPEAKER_00

Otherwise, in that when they're all different, it's probably negate.

Adam

Otherwise, when they're all different, you get it wrong. If you do absolute, then negative one becomes one. You don't want that to one. Yeah, yeah, yeah.

SPEAKER_00

Alright. Wild. J with ligatures sounds amazing.

Conor

J with ligatures sounds like actually why did this one oh yeah, because I I put in stacks instead of min. So technically, I guess, yeah, I guess this would be a lot longer in because there's no zip width index. I mean you could spell it with range pair, but you're gonna need at least uh a before or a fork. It has classify. So I mean actually, let's see, let's see how if I go to BQM, which I believe is right above.

Adam

Translate.

Conor

So this is you know, classif classify, and then this is what uh let's just comment this out for the moment. Is that gonna work? Um, I didn't mean to get rid of everything. So we have classify, and why I guess this needs to be in a fork. Oh right. There needs to be a there needs to be a length in here. Alright, so this looks right. So here's our classify sequences on the right down here. And then now we have our uh enumerate, except we don't actually want to enumerate, so we just want this actually. Um now we want to do our complement, if I can type that correctly. And now we want to do was it plus? Oops, I got rid of something I should have gotten rid of. Then the pattern was we want a min reduce and an absolute value, which is absolutely negate, not absolute. Negate, not absolute?

SPEAKER_00

Yeah, because if they're all different, negative one becomes I can't remember the explanation, but it's it should be minus.

Conor

Oh right, but then uh I'm so close. This is right, I need uh nothing before this. There we go. And so can this be golfed?

SPEAKER_00

Um looks pretty tight to me, I don't know.

Adam

Uh yeah, you can a little bit because you can flip you have a fork on the right, right? But it's parenthesized left side.

Conor

Don't we still need to use something we'd need to or I guess maybe just glue them? Oh, just glue them. Another term, another turn. Oh yeah. I I I I fail to so fork brained.

SPEAKER_00

Um I mean to be fair, like passing wise, I like I personally like grouping, you know, bits and parentheses, even when I write frames and stuff. He wanted it to go off.

Conor

I mean, I I I agree that like you know, if I'm writing it in code, I probably would have I probably would have left it like that because this is much more I agree with Rich. It's much more impenetrable.

SPEAKER_00

Well you gotta figure out like uh the there's two jots there, and one of them's doing one thing and the other one's doing well. I guess it's not, but it is. I don't know.

Conor

I wonder if someone like Marshall, like if he instantly sees this and then knows like that's a unary function and that's a fork, or I don't know. What what are you guys are the pros? Like, uh I guess Rich, you said yet it's still hard to parse. What about you, Adam? Like, do you instantly see these?

Adam

Yeah, yeah, I've gone over the other side of tacit and uh less of a I see I sort of see those screws together, but it bothers me that things that are adjacent with no combinator between them are more distant from each other than things that are uh that are bound together. So people are saying in the chat that you know that uh J with ligatures might be interesting.

SPEAKER_00

Uh I'm thinking valuable concepts uh it still spans the width of two characters though.

SPEAKER_03

So I don't know what we're talking about here. Like it didn't have to, it could be it could be variable width, right? Is it so no but I'm thinking about that the ligature changes two characters into a single character? Is that possible? Yes, yeah, yes, you have, but you never notice because those are not coding fonts, right?

Adam

Yeah, because any normal fonts are enough.

Conor

I'm talking about Jeffrank mono and and sibling fonts that have ligatures.

Adam

If you write F lowercase F, lowercase j in the normal font, it puts the F and the J together. That's where ligature comes from. Using it for programming is a heck. Um so or FI, right? It's a classic one. Anyway, so maybe like for code for API code, I don't mind so much it being variable width. For arrays, they need to be monospace. But let's just say there was a way to make that all work out. Imagine if the spacing between the glyphs was larger when there was no combinator between them, but then the combinator was like narrow and like pulled them together so they would sort of look nicer, sort of healing. Yeah.

Conor

I guess yeah, I'm kind of I'm kind of code golf brain. So my my desire is that like when you have if you if you're trying to replace one plus or uh you know some equivalent with increment, it's like well what did I what did I actually do there? It's only useful if you need some tacit thing and it saves you like you know a cap or whatever because you can keep things in some you know fork mode or whatever. Um but like yeah, tiny apple is much, much better in my opinion, because it's a single Unicode symbol. Anyways, have we have we missed there's been a bunch of um comments in the YouTube chat as we wind things down, seeing as we're a full half hour past the 90 minute mark. I like how Rich was we gotta share the tiny apple. We were it's at 83 minute mark, and then boom.

SPEAKER_00

Oh, I didn't realize there was a desire to keep it at 90. Oh, I think I have a uh was that established at the in the first five minutes when I wasn't here.

Conor

Ever since ever since the beginning of a rake catch, there's supposed to be 90 minutes.

SPEAKER_00

I can kind of yeah, I well yeah, but I did kind of look at the also the links.

Adam

No, I didn't have a a final uh entry here, which is writing Perl in APL, basically. Solving this using regx in dialogue APL. No, the wrong tool for the job. Let's do it.

Conor

Yeah, yeah. All right. Okay.

SPEAKER_03

Although my wife said uh I've got two minutes, so hopefully you can do this in two minutes. I can I think so.

Adam

So so I think this works. I haven't made it into a single function, although that shouldn't be hard. It I think it just it just comes out to a train. So we can do that. But it looks completely insane. Yeah, that okay. So so what's happening here is essentially this is the search function, and it's looking for any one character followed by any number of characters, and then a back reference to the first same character again, which is what we're looking for, right? So any sequence that begins and ends with the same character, and we don't care whatever is in the middle, and it's greedy, so it wants to make them as long as possible, but we want to catch overlapping matches. So this is the variant that says open overlapping matches is set to one. And we don't actually want the result of the search, we just want to know the length of the result, which is the code one for the result instead of returning a text, we return that over there. So I'll I'll shorten this for a moment just over here and and use the uh and symbol. This gives us all the matches that it could find. If we add some more like some B's in here, so we can see that we find the maximum A up here to B, right? So these are all the possibilities, all the candidates. But we don't want the that, we just want the length of each one. So we replace this with a one. So this is length eight. And then we want to subtract, but remember this counts the length of the first and the last character included. We only want actually the length of of the middle one. So we could extract the middle one, but it's easier to just uh to just subtract one from it here. Um is that actually true? Is that the shouldn't we subtract two? Let's make a shorter example just to see here. So this should give us yes, oh, it gives length two. So we need to subtract two over here, and then there's one problem that is if there aren't any uh matches, we need to get negative one. So if I if there aren't any matches, it gives us an empty list, and then we try to do the maximum empty list, that's no good. Uh because that gives us the identity element, which is negative infinity, so we don't want that. Um actually, and we could be trickery with this, but whatever. So this is the uh this gives us three, one, two, three. That's this one over here. And if there aren't any matches, we get negative one because I just stuck that in there. The problem is we get inf negative infinity. So there is something we could do here. We could be a little bit tricky and just say like negative one with maxed with that, but that's just that's just silly. Uh it doesn't save save us anything. Anyway, so this is a uh this is a solution uh using ragex in dial like APL. Forget you ever saw this. Don't do this. This is for sure going to be the slowest solution of them all, and it only works on characters. So uh yeah, never mind. You will also fail and all kinds of other things. Well, now you've seen that.

SPEAKER_01

There we go, folks.

Conor

We should call it a day. He didn't do it in two minutes, but three and a half is pretty good. And uh doing Pearl better than Pearl uh you know does it. Technically, you know, this problem came from Pearl Weekly Challenge, but every once in a while I look at the Pearl solutions and they they try and make it look like Python and like very variables all over the place. And uh I tried to find the solution, they don't have it, but I the solution for the first one is like hardly using regex at all. So APL, doing Pearl better than Pearl, and I guess that's where we'll leave it. So we saw what did we see? We saw uh we saw some J, we saw some APL, we saw some Tiny Apple, we saw some Wiwa. We did see a little bit of BQN at the end too, and uh the only thing we didn't see is Cap. So I guess we gotta bring Ellias on or something to make up for that at some point. Uh thanks to Adam and Rich for um hopping on and and chatting about this. I think this honestly turned out so much better than not that I thought it was gonna be bad, but I didn't think it was gonna be one of our like, you know, better episodes of covering a bunch of different primitives and solutions. If folks have their solutions, uh post the live recording of this. Feel free to share them in the the YouTube comments. You can also reach us at arraycast contact at arraycast.com. If we have access to the email, we I think we kind of quasi got blocked out. Adam I need to figure that out.

Adam

Uh we should have continued.

Conor

Luckily, uh you can log into the YouTube account uh without having to log into the Gmail first. So I was worried we lost access to the YouTube account, but we still have access to that. Uh once again, thanks. And I guess with that, we will say happy array programming programming.

SPEAKER_00

Uh it's been a while. Happy array programming. I didn't know you can do it at the same time. It doesn't matter.

Adam

No, no, the way we do it at the same time is that when he says that we'll say, that's when you have to say happy array programming.

SPEAKER_00

Yeah, yeah, but back in the day, in the old days, it was he'd say it and then everyone would say it. Yeah. And if we didn't even say, that's because you would fix it in post.

Conor

But now we're live, things are different. Anyways, thanks guys. We'll uh we'll do this again sometime. All right. Great to see you.