Conor

Welcome to episode 126 of Arraycast. I'm your host, Connor, and I'm with my temporary co-host, promoted, because he is the only panelist, which we will be talking about a little bit more. We're gonna go around and I guess do brief introductions because that's just the way we've always done things, and then we'll hop into a couple announcements. So over to Adam.

Adam

Right. So two things coming up. The first one is the deadline for the APL Forge submission. It's the 22nd of June. So it's just coming up soon, uh in a week. Um, so that's the sort of competition where you can submit uh projects in or for APL. Um, and then we have a committee of people looking at that, and you can win a prize and a trip to the upcoming APL user meeting, uh dialogue APL user meeting, um, which is going to be in Eastbourne uh on the 12th to the 16th of October. Speaking of that, it's registration has begun, and well, you can't see the full schedule yet, but you can see what the workshops are going to be like um and the schedule for that. So you can have a look.

Conor

All right. I think we technically skipped your brief introduction and went straight into announcements, but that's all right. Uh they know me by now. They know me. Um, I I actually also have a uh it's not an announcement, but it is a call to action of sorts. Uh so whether you're listening to this live or you're listening to this on the audio recording later, uh, we are looking to, and I know that there are a handful of folks that have reached out via email or Twitter DM or Discord. I have the people in mind that I'm thinking about that uh DM'd me on those platforms, and I think actually maybe one person reached out to us on array uh contact at arraycast.com about joining us as panelists. So we're looking to grow our team of one panelist team. I mean, Rich might be joining a little bit later. He's in a meeting right now, but uh just like last time, he might be joining us. If you are interested, uh, because we don't want to miss any of the informal applicants uh that might have emailed us anytime between what is was it, November of 2025 and now, send us an email if you're interested. Um we might be doing something a little bit differently. We might not be having necessarily all permanent panelists, we might just have rotating panelists, so different voices from episode, but you'll hear the same kind of recurring voices. If you're interested, uh drop us an email at contact at arraycast.com. If you want, add, you know, uh one or two or three sentences about uh why you'd be interested in joining as a panelist and your background, if any with array languages, you don't necessarily have to have uh array language experience. Uh and we'll go from there. On top of that, not only are we looking for panelists, but we are looking hopefully for someone to not fully replace Bob Terrio, but to replace the part of his job where he would reach out to guests and set up the you know recording timing schedules uh for guests, because we have a list of guests we'd like to start bringing on, but Adam and I are both very busy folks, and we thought seeing as we're growing the team and a part of that original team was someone that had the time to reach out to guests and uh set up the you know schedule of recordings, uh that'd be fantastic. So if you are not only interested in being a panelist, but would also like to do that, or you're not interested in being a panelist, but for whatever reason you like that kind of managerial organizational stuff and you'd like to be involved in kind of setting up who's gonna be the next guest and sending out those kinds of emails, uh also shoot us an email at arraycast contact at arraycast.com. And we'll leave it at that. So if you're interested, shoot us an email and we will review those over the next two weeks to four weeks, and then you'll probably hear some announcements on this podcast at some point, and we'll be reaching out to folks in between now and then. With those two announcements plus a call to action out of the way, links as always, not for the email, but for the two things that Adam mentioned will be in the show notes. We have another episode of Adam Live Codes and Connor Learns Things. Uh once again, we're gonna be solving a couple Pearl Weekly Challenge problems. Well, we'll guarantee we'll solve one. I think the first one's a little bit easier, and I actually don't have too much that I'm looking forward to like uh pick up a little tip or a trick here, although I'm sure I will in watching Adam do it. I'm more interested in getting to the second one, but uh we'll see. Maybe the first one will be more interesting than I anticipate, and it'll take up the whole one, and then we'll have to kick uh down the road the second one. So, I mean, I'm not sure if you want to screen share Adam, seeing as you're gonna be live coding in a sec, and then you we can uh describe the um what do you call it? Uh problem statement, uh, which I'm now trying to see you. Well, yeah, we'll just we'll let you live or are you are you gonna uh screen share? I I can, but I don't even know what the problem is yet, so I'm sort of scared here. He hasn't so I mean I I linked it in the uh the chat, and I guess actually that's probably everyone can see on the live stream, actually. It says Raycast 126 and uh pro weekly challenge uh 377. So if I close this, no one can see that anymore. Anyways, we'll wait for Adam to screen share, and I believe the problem has something to do with substrings.

Adam

Uh okay. Well, I guess I can I can start sharing my screen and see if I open the right window here. Uh let's see. I've got like a thousand Chrome tabs. Let's see. So I believe this is uh this is the right page, 377. That's what you said. Yes. Okay. Let's see if I can figure out how to read this.

Conor

You gotta scroll down all the way past this nonsense. They always do like recasts. Then they do stats and then they do task one.

Adam

Here we go. Okay. I guess we can make this full screen to see this. You're given a string, great. Write a script to find whether any substring of length two is also present in the reverse of the given string. Okay.

Conor

So pretty straightforward. The cut the problem is called reverse existence. You're given a string. The first example uh was ABC B A, I think. And the problem's asking you to return a Boolean, a one or a zero, based on whether any substring of length two exists, has its reverse in the string as well. So for the first example, AB exists as B A at the end of the string. And in general, any palindrome is gonna return true by definition. Um unless it only has one character. Yeah, I I guess I was about to say, unless if you have a one-character string. But then the string in example three, A B C D is gonna return false because it does not have um, I guess by definition, you're also gonna need duplicate characters.

Adam

Um not that we're gonna check it out. If it's duplicate characters, then then yeah, of course. So I mean, maybe there's a a better way to do it, but I think very simple. If we start by looking at the pairs that are there, and then we can look at what at the pair is reversed, right, and check if any is a member. So these are those uh the reversed, and we want to check if there are members of itself. So they're all members, right? Because this is a f a palindrome like this. Uh so that's obvious. Um, A, B, C, D, all members. But if you want to do something the way they're not all members, maybe have a like a normal test? Banana, sure.

unknown

Okay.

Adam

Uh well, I was gonna say A B C D should return all zones. Oh no, this is a mistake. This is a mistake, this is a mistake. Uh the reason is that I I don't want to reverse the list of strings, I want to reverse the each in the list of strings. Okay, so there we go. So A B C D, and then none of these are right, and banana. These are right. So all we need to do is we want to see if there are any. So that will do it. This is not a proper function, it's just a sequence of of operations, but we can we can just wrap it. So this is how I'll do it initially, but I think we can be maybe slightly more clever.

Conor

I was gonna say this is already better than what I did. Uh okay. What let me let me find the is it clear how it works? Everything, the structure of it. Why did I I guess that's the thing, is I I don't have my membership and find and uh the epsilon um functions, I guess, committed. And so I always do that thing where you like uh just try one, make a mask. Yeah, but I basically, but I I guess I did it one by one. I didn't um so like I have like a reverse of each one at a time. It's so much more complicated.

Adam

Um, this is so we have a question in the in the chat if it's guaranteed to be only two letters, but yes, that's the problem. Yeah, just find the substring and link two. So this is this will be here's another thing we can do. Uh we could put a swap here, which is the same thing as giving a negative two over here, but that doesn't really matter for now. Um, and that gives us also the reversed substrings. So we could look at whether these are members, right? So we can actually make it a little trained. This is excessive work because we're making, I mean, it doesn't really matter. We're making um the the substrings twice. So we can say, are the normal order length to substrings members of the reverse order member linked to substrings? And then we can write that. So that's I mean, that's just a different way of stating it. Whether we generate them from that, I'll say it in a different way. Doesn't really make a difference.

Conor

Yeah, this is well, like I said at the beginning, probably I was gonna learn something even though I wasn't expecting this to be the problem. But yeah, this I don't know why because I guess, yeah, once this is the membership glyph. Yeah, and if you've got substrings against substrings, I guess that's the thing, is I didn't think to search the substrings in the reverse substrings. I kept substrings versus a string, and so then I guess you could do that. Yeah, yeah, but it's a way worse idea.

Adam

Um, but if you do that, it's a if you if you do it like this, right? And then for each one of these, we want, I mean, we want to find out if it's a member or if it's found in the entire string. Oops, a mistake I make here. Oh, missing the argument. And we don't need an each, we need the each over here. There you go. So now we say for for each, we get a mask of the places where it appears, which would be more interesting if we're actually looking for specific places where specific substrings are found, but it we're not, so it doesn't really matter. So we all we need to do is see if there's anyone in here anywhere, which we could couple different ways, you can I mean just like that, we'll do it.

Conor

That was not one of the ones I was thinking of.

Adam

I was thinking of uh or ravel or or um yeah, we also know they're the same length, so I guess we could even do it with a rank, but I mean it's there are many different ways of doing it, they're not especially attractive. We're looking way too much here.

Conor

So, my I have a question about why did you default to enclosing the original string um versus I guess when I did it you could have bound it like this instead.

Adam

Yeah, that's what I did.

Conor

And this is why I wanted to do the problem uh in the first place, is because in order to if this is the way that you originally spell it, which is what I did, um minus the find find, I did uh or reduce or reduce. In order to go from order to go from that uh to tacit, you end up having to kind of do the backflip in order to get what you originally put, which is enclosing the string in order to put it in a flip. It's one uh it's one worth getting to hear from you. Why did you put the why did you do the enclose original string first? Uh and probably we should slow down a bit to explain this to the audio only listener. And then also too, this is like a trick that I learned. I I consider it a trick at one point. Um wait, I actually don't know, I don't actually understand what you've done now.

Adam

So you've avoided or no, you have uh uh commuted because it's a it's a fork over here, an AGH fork on the left. So that means it's it has to be parenthesized or bound, but we can't bind the two to a derived function anyway on the left, so we have to parenthesize anyway. So then I just immediately went for okay, I'll swap the arguments. Um and that's that's what I did here.

Conor

Yeah, that's really that's really hard to do because you're doing uh each on the dyadic and then a commute in order to do the enclose. That's uh yeah, if you're seeing that for the first time and trying to parse that, uh it's a bit tricky. But yeah, walk us through so is why you reach for the enclose first and then this in general.

Adam

I I don't know if we call it more functional, but like I prefer keeping things in their right places instead of composing them. Composing on the with a what's not called composition, it's called binding. Binding a right argument is somewhat messy because it converts a dadic function to monetic function with the remaining argument slot being on the left. But being that it's now a derived monetic function, that argument goes on the right. So maybe that's a bit complicated to explain in this context. But let's take minus, for example. So if you write like 10 10 jut minus, that's a monetic function. It's pretty easy to understand. It's 10 minus. But if instead we wanted to write the minus 10 function, right? So this takes an argument over here, so it's 10 minus 100, negative 90. If we wanted to write the minus 10 function, which we'll have to parenthesize in in application, but that's not so important, and then the argument over here, then notice that uh this argument which appears to the right, um, the argument to the minus 10 function actually becomes the left argument to minus, even though there's no explicit swapping going on. That means things are jumping around a bit. I prefer right arguments to remain right arguments, left arguments to remain left arguments, or being explicit about the swapping, which we can do with the commute operator. So so that would might be one reason why I prefer to enclose on the right instead of binding. But sometimes I'll do it.

Conor

That makes sense.

Adam

And then well it's also not a very meaningful function. I mean, if you bind an argument, you sort of want the derived function to be meaningful. But what is the find in omega function? This is a weird thing. It's like look for them look for ones, that's a meaningful function, but not look in something.

Conor

Right. And then explain. So that makes sense. It walk people through this um enclosing uh a string or a vector and then performing the dyadic operation each time, because a lot of times, especially when you have the original pattern where you're trying to bind, you know, partially apply an argument to a dyadic function in order to apply something over, like it took me a while just to stumble into this kind of pattern, whereas, like if you want to turn that into tacit, the pattern is to enclose it and then do some dyadic operation each. Yeah. Like one, is there like documentation somewhere to point people at this? And and if even if not, like uh what's the uh path? Is it is the path to discovering this just that is the more and more you program an APL, at some point you will kind of stumble into this pattern, and then you'll if you're lucky, store it in your vault of way of ways to solve things tacitly?

Adam

So I I don't know, we can look at the documentation for it, but I think uh it is a problem people have with the each operator, is that especially if they come from another programming background and they think of they think each is just oh that's just my map, but it's not then they then they expect a single thing on the left and multiple things on the right, expect it to to map over. So if we take like um A B C and we want to catenate just for ease of usage here with uh X, Y, Z, I think so it the actual mapping, which really means stepping over elements, right, with sort of iterating, um appears on both sides. So uh it's a double map. This usually would have to write this either with um explicit iterator counter that you then index in other languages, or you have to do a single map that includes the iterator and then use a single indexing for the other arguments, which makes it asymmetric, but each is completely symmetric in the API. So the way it works is that we have got the scale extension. We can have a single element, um that's a bad example that maps to both uh to all to all the elements of the other argument, and we can have we can start off with many on the left and have a single thing on the right, and it will map the other way. We can even have a single on both sides that's also allowed, then we get an an enclosed result. So the way to so we can sort of say the one to many is a solved problem. So if we want uh one side to be considered one, you sort of want to reduce the problem to that date. So we need to change this vector that's on one side or any array really to a scalar, and we do that by an enclosure. So each actually opens up enclosures, actually digs into an array, which can be a little bit hard to spot when you're dealing with simple arrays because we've got this floating array model, but really it's it's reducing the depth um of the arguments by one. And re what it happens here with the um with the each, where we've got an array with multiple elements on the left and a single array that contains multiple elements on the right, is that we reduce the enclosure level by one on both sides. So that's so we take first the first element of the array on the left, and then on there's only a single element on the right. So we take that element and disclose that as well, which reveals the entire array that's inside. And then we do the same thing with the second element on the left and open up on the right and gives it an entire array. That's why effectively it becomes a many on the left to one on the right. I know the K language has like explicit separate each operators or adverbs, like each left and each right. Um, but in APL, that's because they don't have, I mean, the cause, they don't have the concept of an enclosure, a scalar enclosure. You can only do one element lists. So it's a whole different way of doing things. We can write an each left each right operator in APL, but it's easier to do it like this. And so too, we can yeah, so this this maps each element on the left to the entire array on the right. And similarly, we can do an enclosed the array on the left and the catenate each to an unenclosed array on the right, and that maps it the other way. So these are the two different types of each. And then again, as before, we can just do a simple each with no enclosures and that pairs up the individual elements. It sort of hints at an operator that's missing, the depth operator, which PQN has. I think that was in my initiative. Uh J actually has it called the level at operator or adverb, but isn't much use there because J is much more about um dealing with higher rank than deeper depth. And then the complete equivalent thing is that we can bind. So the binding, uh this long left scope of operators, so the each here sees if we write quote a b c quote jot comma each. So the each sees the quote a bc quote jot, comma, as a single thing. It's a single derived monetic function that's applied to each element on the right, and that's why it has that effect uh of concatenating the entire left side because it's been bound into the function to each element on the right. The other way is interesting because we can't just put uh a jot on the other side. That doesn't make sense syntactically. We do want the jot in this position immediately to the right of the concatenation function, but we have to put the operand to um to the bind operator immediately next to that as well. And then some people end up in the especially with a neuter APL writing something like this where we have got a left argument and then comma jot right argument each, but that's not right, of course, because the comma jot right argument each is a Single derived monetic function, it takes a single argument, which is on the right. So the ABC now needs to move over to the right to get that effect we had before, which is that's the sort of thing that can be confusing. Like positionally on the line of code, the left argument is on the right, and the right argument is on the left.

Conor

Yeah, at least for me though, when I was learning APL, this was easier to get to. Um because it well, I guess it just depends on the order that you learn things. But like for me, coming from Haskell, um where partial application and like binding is very common, it it maps like very easily to APL, right? You have your bind operator and you can partially apply something on the left or right. And so if you know that you're trying to fix something uh and you're trying to apply that unary operation, it's easier to without learning the uh, I guess, uh full uh depth or like comprehensively understanding what each is doing and how if you're adjusting it's um you know the with enclose, like that's uh an extra thing that you need to learn. And you can get to what's on the screen right now, just partially applying something on the right, putting that on the left, and then eaching it over whatever you need to. And so that was typically the way that I would do things until I actually don't know how I I guess one day I just was messing around, yeah, and then I was like, Oh yeah, if you enclose it, I guess that kind of makes sense. You're um although I would have I ever explained that what was happening is that the each was reducing um the depth by one, and uh I don't think that's how I would have ever explained it. Uh I think I was I think I just knew it as like a little idiom that you enclose something on the right and then then it'll apply over the whole thing.

Adam

Um so I mean I guess J is a bit more formal about things in a way is good, but I think practically speaking, pragmatically speaking, it just comes in your way more often that it does your service. So there in J, they don't have a each primitive, but they do have an each like standard library word, and it's all it is is under this close. But the under they have is they have two different types of compositional operators. Uh the the close and uh white, I don't remember what the other word is, uh uh application. And so what it does is it it does an operation, but on each um element or on each cell, um it it does some application, and then it applies the function and it joins everything to back together again. So really we can see each as being a uh rank zero under disclose thing. So or or well, we say all the way around, it's this close under rank zero. So if we if we think about it, this we can try to define the dyadic uh each, but let's just do it for a single single thing. Well, actually, let's make a monadic because it doesn't really matter, the pattern is the same. So let's let's make the each operator, and all it does is we have an argument and we have a function that we are applying rank zero that's on every um element if you want. But before we apply the function, we're going to um apply it a disclose first if you want. But since it's rank zero means there will only be one element, so there's no difference between uh a mix and they um and a first, they just disclose, and then when we are done, then we package it down again with an in-close. So this is sort of an under. We don't have the under operator yet, right? So but we are disclosing, applying the function, and enclosing, and then that gets collected into the argument. So we can see here if you say abc df, so we can do a reverse each and reverse with our fancy new operator, each gives the same result. This is really the definition of each. And the dyadic form is exactly the same, except instead of applying um with an uh function atop this close, it would be a function over this close. So we're just applying pre-processing to to both sides. That's the whole definition of it. Uh, then we need an alpha over here. So now you can see that it's explicit that this disclosing, and then you can also see why uh why enclosing sort of negates the preprocessing of that side. If we enclosed omega here, then we then when we apply rank zero on omega, that's the entire array, because it's enclosed, so that's a scalar, that's the whole thing. So that doesn't matter on the right. On the left, of course, if we have multiple elements, it will go into each element, and then we disclose it, which it's just a single enclosure, so that gives us what's inside it. And on the left, we it does its thing on each element, and so on. Does that make sense?

Conor

It does, and uh, maybe I will take the time to add chapters to this YouTube live stream after it's done recording, and I'll call this each deep time each deep dive and tacit tips or something like that.

Adam

And so then we can just point people to the timestamp uh whenever they have questions about because this is TC is a trace operator uh in the defense workspace that draws out. Let's turn off boxing here, it will be very flooded. Um it draws out on the screen um the steps of computation wherever we insert it. So it's just a magnetic operator, we can attach it to any function. So if we attach it to every function, then we can we can see exactly what's going on. So here this function the disc close and we'll put a tc on that, and the main function we can put a tc on that, and the in-close we could put a tc on that. Okay, so we're redefining our each like that, and now we're doing what we did before. A b c comma each xn. So we can see here that it first thing it does is disclosing the x gives us x. Disclosing the a gives us a. That's there's not much there to do. We're picking those, right? And then we concatenating a and x together that gives us part of the result. And then we take the next step. We enclose that result, and that goes into our result array. And then we take the next one. The y's and the b's and so on, that we'll step through. Now, if we enclose here, we can't really see much, but we'll see a little bit of the spacing will be increased. So we can see that there's extra spacing here that sort of indicates that it's in-close. So we're disclosing that, and that gives us the unpackaged form. So it's just just negation of that in-close. Rest of it is sort of the same. Um, all right.

Conor

Well, I mean, we've spent 30 minutes on the first problem.

Adam

I think we've got not quite yet. There are other ways to do it because this is the pro with your problem. So we've got to solve this with regex, man. Otherwise, it's all right. Well, we'll let you see. We'll we'll time box the regex solution to uh to uh how well how quickly I think I can do it pretty quickly because we want we want the one letter followed by um another letter, which uh no obscening thoughts here, uh and then we want any any sequence of characters followed by the second one and then the first one, right? This would mean if we have if this matches anywhere, then we've then the answer is true, right? So abc D shouldn't match any, we've got nothing. A B C B A. We found that, right? So that's the first two and the last two, but we're not actually interested in whether or not uh and where what the answer is here. We just want to know if there is such a thing. And banana, we found an anna, right? So we found an followed by something followed by na. There might be multi multiple of them, but it doesn't matter because the first one is going to find, well, is is enough. So if we write like uh a b a and uh xyx, we should we'll find two. All we need to know is how many are there, and then we can take the sign of that or see if is one greater than uh sorry. Yeah, yeah, is it more more than equal to one? So that would be the solution as well.

Conor

That was very fast and uh still not as short as the APL though. Um no, I know I well technically it is APL, but not your original solution. Asher in the chat, in the APL, which I believe is your co-worker, um says that uh he just posted a bunch of wacky ways to do the original problem ordered from clear to short, but I think I think YouTube is eating all of those solutions. So you can just send them to me in in normal chat. I was gonna say either send them to me, get them, but in general, that's only a good solution for viewers that know uh how to send them to you. So I'm going to array cast github repo, and I'm creating uh a new chat, and I guess we'll just call these um what do we do? We call this uh I guess it is a podcast episode.

Adam

So here are here are Esher's uh solutions. So what's going on here is he's doing an auto product of the array with itself, and then he's looking at whether we have any diagonal matches and any full matches that would be if they are right. So any diagonal matches that's if we have a reversal, and any full matches would be if we have duplicates, I believe. And so and he flattens that and I and find out if there's any uh anyone in that seems a bit overkill to me, but sure. This is a similar that's exactly the same, just instead of looking for these patterns, then he's just doing rotations in to match things up, and then seeing if there are any such patterns. He's still more of this idea finding the indices and seeing if uh if there are any indices that are off by one from each other. Okay, that's what you mean by wacky. Yeah, uh, I agree with him that uh wacky wacky is a good description of these.

Conor

And if other folks have solutions, because last time we got uh a very cool Wii Wa solution at the tail end. Um but yeah, J, BQN, any Ray languages, tiny Apple, feel free to you could try posting them in the YouTube chat, and then uh if it doesn't work there, you can post them in the GitHub discussion link to Raycast. Uh all right, let's move on. Thank you for those submissions, Asher. Those are um uh very cool. I am very interested to see uh Adam solve this because my solution to this was pretty terrible, and he already improved upon the first problem, so I'm he's almost guaranteed to improve upon the second problem. The question is, how nice will it end up being? Time will tell. And the problem statement is prefix suffix, write a script to find if two strings in a given array, which is uh an array of strings, uh, such that to find if two strings in that uh array of strings. So there are only two strings in the in the array of strings. No, no, no. There are multiple strings, but you're looking for two strings within the array of strings where string one is a prefix and suffix of string two. Oh, okay. You you perform that option.

Adam

This is this is a bad bad formulation, right? It says write a script request if the two strings, if there are two strings, string one and string two, such that, right? So string one is a prefix and suffix of string two, return the total count of such pairs. Okay, so uh we I guess the easiest thing is I mean, we could do fancy stuff for performance with looking at the length and sorting out things that would be impossible. Um but easiest thing is just to uh to do an outer product. Let's start by uh importing this. Array is quite JSON. We've got to turn JSON this off. Okay, so we've got our array. Maybe we should turn boxing on again. Box on. Okay, so we've got our strings here, and then we want to find out how many are uh uh prefixes and suffixes of each other. So first we have to figure out what is mean it's a prefix and a suffix. So I think the I mean we could do a find and look at the at the beginning at the end whether there's a one, but I think it's easiest to just do a reversal. So let's say these are again sort of funny examples, but okay, let's take a b a uh that's a bad example again. Okay, let's do a b and do ab X. So here this is a a prefix and a suffix. So for prefix, there's I like to compose things like this. So it's the uh no, it's not even that, it's the first. Sorry. The first of the find. That that is the prefix function. That means the left argument is a prefix of the right argument. It's technically speaking on lots of unnecessary work, but hopefully one day if my colleagues will do their job right, this will be optimized and it will stop looking. Like this composition, or even with a thunk or something, it will stop looking after the first element because this it will never return true otherwise, uh, because we throw away everything but the first element. But this is this is the first, right? Now, for suffix, the easiest thing to check is whether this in reverse appears at the end over here. So we can just do that with a uh with an over reverse. So if we say make this AC, it'll say no there, right? So we need to apply this function twice. One with with the over. We can't factor that out because it's really two different sets of data it's working on. So if we want to make sure that both of these are true, we write first a top find, and first atop find over reverse. So this is the uh this means that the condition here has been met, and uh then we want to do this as an outer product on all the the array of of strings. So that's this. Now um they say the result is is four here, but of course there's a diagonal going down here, so that's a bit of a problem, right? Because they apparently they don't count uh duplicates, right? You can't say the string one is both a suffix and a prefix of itself. And where but I suppose they do say that uh well interesting, an interesting thing is what if it's a complete match as well, if they have the same length and they are because if the duplicates in the same way. There is an example below. Let's see. No, this one, yeah. The one. Okay. That is interesting as well, because if you take that example, abab abab, right? So so there they don't count the duplicates either. I would say that the first abab is a prefix and suffix of the second above, and the second above is also a prefix and suffix of the um of the first one, right? But they don't say that either. So apparently what we have to do is we have to mask out half the triangle, just in case, um, and and the middle diagonal. So we can we can do that. So if we if we look at a masking here, so if we make we can try to start with this. Oops, sorry, that should be this. This is a a masking triangle to isolate just the elements that we want on the strictly top right corner. So this would be with a count. We want to tie these together, the top over here. That's our function. And we can adjourn that in here, this and this. So this gives us our matrix, and all we need to do now is count how many ones there are. So we can do that, there are multiple ways to do that. But classic one is the sum of the rabble that's for it's looks sort of noisy, but it it's fairly readable, especially if you put them spaces in.

Conor

That's uh God mode APL programming, folks, that you just witnessed there. And um uh let's all just have a moment of silence for this beautiful expression that uh Adam has uh put on. Rich, what are you doing in the chat? You're supposed to be on this podcast right now. Join the call, man. Or is or is he is he virtually attending another meeting? Uh and I don't know. He might he might be in another meeting but secretly looking at this.

Adam

Yeah, we call them uh Rich says that it's two tested.

Conor

Uh I disagree. Um, well, so my first comments are is that mine actually isn't too far off. So I I mean I had the prefix idiom um first composed with uh or I guess it's is it find is the name of the glyph? Yeah, first composed with find. I didn't I missed this over trick. So I think my first thought was what I wanted to do was under, but I guess it doesn't need to be under because you need to reverse it at the end, it doesn't matter. Exactly. So is that is that a general rule of thumb? So yeah, my my for for those you know that uh are only APLs and not familiar with under. I mean, every uh is everyone familiar with under? Under is like you know, as Adam likes to say, under anesthesia, you apply an operation and uh then you do some other operation and then you apply the reverse if there is you know a defined one for that. So under reverse, the inverse or reverse of reverse is reverse. Yeah, clip that, put that in a TikTok. And uh but in this case, because you are just getting back a scalar, you don't need to reverse the result. And so, yeah, that's my question. Is that a general rule? If you only need to apply an operation and you don't need to worry about like undoing that operation, can you always use over? I guess not really. It's only in the case where you have two arguments, and also I don't even think under necessarily would have worked for this, would it?

Adam

Oh no, under would have worked because the result is a scalar, and reversing a scalar, it doesn't do anything. So right, right, right.

Conor

It wouldn't have made a difference. It's just unnecessary. And so, anyways, that was the first thing that I saw that you did was the over reverse, which is really nice, and then I did it something a little bit different. Instead of building up the upper triangular matrix and masking things out, I did a here. Let's let's admit Rich. Uh look at that from YouTube comment section to uh to uh 48 minute uh joining guests. Welcome, Rich. We're deep in Pearl Weekly 377, and now you're here to reign on our tacit parade.

Rich

Look, all I'm saying is look at that a top, a top abomination, a top a nation.

Conor

A top a nation. Let me tell you, this line of code is gonna get more people into APL than this like JavaScript looking like everything's got a variable name. That's my that's my pitch.

Rich

Well, I didn't I said it was too tacit. I didn't say you should name every part of it and then also too, look at him not aligning these arrows.

Conor

I could go back and fix that in post or whatever you want to call it. Is it if this helps you? Array box does it automatically. Uh um but yeah, the while Adam is still typing this up. Uh it does a little bit. Um, okay. And uh but the thing, so the I was saying that the thing that um uh Adam did where he was uh building up the upper triangular matrix and then masking things out. Uh instead of doing that, I did like a uh and I don't know if this is an idiom, but it's a pattern that I use sometimes where you just you get an IOTA sequence, you rotate your original array of strings um by your iota sequence, and then you perform an operation where you have you know one string versus the rest of the string. So kind of like the head tail trick if you're familiar with Haskell, which which one's better? Uh you know, pick your poison.

Rich

Well, I was wondering when I was watching that, is this is the description they often are ambiguous. Is it ambiguous enough to say we go? You could just stick a unique on the inputs and then get the number out.

Conor

The description is ambiguous enough, but um I think it's not enough examples that is not gonna end up working.

Adam

Yeah, right. Unique might not work, it's just that it doesn't I don't know. I don't know about this thing. They say there's only one. And we do things with themselves. Yeah, we do things with themselves. So you should count it. Yeah, I think that will work. Um but we also it's not enough because this will you still need to take them away from themselves. So you still need to do something about the diagonal. So certainly that's not going to be enough. Because you even if we take the first one, uh, we said like uh every everything in every every string gets a match on its own because it's its own prefix and suffix. Yeah. So therefore taking away the is not going to yeah, so you have to get rid of the diagonal. Getting rid of the diagonal, you might as well just get rid of the duplicates with the doing top right instead of diagonal. It's a matter of switching this for an equal sign. So that doesn't really help. But maybe this is more readable. And we could even define this as a function and then apply it at the end.

Rich

Um it's a possibility. I really just mean once you've got that many atops, it's a deepen.

Adam

No, it's but that's the it doesn't really help because if you go back to this, and you're saying you've got lots of atops. Let's try to see how what it looks like as a defen then. So yeah, this is a defense deephon at all. This is like that case.

Rich

That's uh your your the far right outer product, you know, I'd leave that.

Adam

You leave that. So this is a deefen, and then this. I mean, okay, you're gonna compare this with with this, you say.

Rich

Yeah, in so much as an argument that has been made many times by many people, that here you can sort of see plainly what bits are applied monadically and to the argument, whereas with if we put in a little bit of spacing like this. Well, meh. No? No, I still think the defense just a bit more at a glance. Oh, you can but you know, this is uh very controversial topic.

Conor

Well, I was gonna say we can dedicate the last uh 38 minutes of episode 126 to uh once again how much tacit is too tacit, because we've got, I mean, the audio listener is just being like, what are they talking about? They're just all like, what about nah? Uh-uh. And we've got three solutions. We at one point had four. If you remove the spaces from the original tacit, and there's a plane flying above uh me right now. I'm not sure if that's getting picked up, but you know, the first one on screen is the most tacit. It's it's gonna for those that like uh, or sorry, it's the most explicit, for those that like tacit programming, it's gonna break your heart because the uh two character three if you're using the compose glyph uh has been named prefix, which is six characters, you know, a few more if you include the spaces and the assignment. Uh and then it's omnifix for looking at the prefix.

Rich

Oh, it is still completely tacit up until the last line. It's just that it's the the composed functions. Adam, if you're talking, you're muted. Or am I?

Conor

Or Adam, if Adam's talking, yes, you software. Um, which probably just was his uh um headphones microphone cutting out of it.

Rich

All right, this is very this is functional programming people of this sort of thing, you know, compose your functions into new named functions and then recompose those functions. Can you hear me? Yeah, I can hear you, Adam. You sound good now.

Adam

Yeah, so so I'm saying the yeah, that it's sort of what's the point of making it verbose and readable when you could take the time to slowly go through if it's slow, right? To go through these parts. I'm not saying you should remove all the spacing. The spacing, I think the spacing here can help a little bit to see the structure, but there's like it does what it says on the tin, right? This what do you mean by ones? It's ambiguous, but this is completely unambiguous, at least if you know that it's a monetic context. And the same thing here, like okay, the top right corner. I guess that that's works as a name for it. Although it calls it.

Rich

It's a in this case, yeah. But that's uh, not ourselves, exactly. You want to name things differently.

Adam

I can this sort of construct is so common that I'll instantly recognize it. I mean we maybe replace some of these with jots instead if you want, but it's it's the same thing. Right, but mod argues well again, I don't remember. And this one as well. This one is the is the tough one, right?

Rich

Where we this one is slightly harder to read. I didn't even get to the finish uh describing in an audible way what all of the things look like. Is it even possible?

Conor

Oh uh yeah, I mean so the the descriptions of them were and I guess well that's a good point, is that the I said the most explicit, but really that is Rich was correct to point out that technically the first four lines where you're assigning names to uh components of the full tacit expression, that's all tacit. It's actually it's just naming. What do you what do you technically call that?

Rich

It's I mean that's very if you look at any of the D Funds workspace, defense.dialog.com, look at the code in there, it's very that flavor. It's name a line uh as a definition of a thing, and then compose all the definitions or put all the definitions together into the final answer, which is and it was very much inspired by uh functional programming, that way of writing stuff. The pure symbol thing is slightly more controversial, if anything.

Adam

So we have a comment from the unpronounceable participant name in the chat saying that uh the tacit code is unambiguous if you know the aerity, but with hardware keeping track of all the atops here. That's what I'm saying. But actually, atops tell you what the arity is. If you have an atop, you know that whatever's on the left is called monetically. There's no other way. So if you go up and read I'm just you know that this plus is not a pairwise plus, right? It's and you know that this outer product here is monetic, and because of that atop, and you know that here yeah, yeah. So all the all of these, the same thing goes here.

Rich

If you know that you have to read several of those to figure that out, and each piece, and it's not yeah, and it's like in the fork, you know, you've got some extra noise to detangle between the tops that are either side of the and, whereas the omega, like that's one omega, and then the rest just reads as and just passes as APL. Yeah. So you've got one indicator there saying this is uh monadic. Whereas in your like a top account, a top outer product.

Adam

So maybe maybe some kind of um um compromise thing where we we'll just define the omnifix immediately. We say this is what the solution asks for, right? We we really it's trying it's defining this term of omnifix. So we're saying omnifix is space it out nicely. Uh this and what we want is then the rest of this. I mean these are some qualifications. How about that?

Rich

Oh, I see that array box kind of link. Open my link, Adam. I wanted to see how crazy it looks. Uh okay. I mean, I'll say to that respelling that my problem wasn't with the the omnific side of it, it was the other side of it that I'm not a fan of. I do this is quite interesting that uh array box only you know can deconstruct. And the thing is the facet function, it can't do this with a defense.

Conor

If you if you uh like if you go to the parenthesized component and you just select that and then you go shift enter, uh you know, it'll zoom in on that. And then I didn't add this feature. If you go and hover over each of the glyphs in in there, like uh a user went and added this, and so that's so nice. Yeah, love it. Anyways, like I'm not saying this is an argument for you know, one versus this is this is a tool to help you get over the deficiency, yeah.

Adam

Uh you know, that it's um that you call it deficiency, but I'm saying uh a dictionary is a tool to help you get over the deficiency of the language that the words don't hold on. The words too many words the words in in English, for example, do not carry their own meaning, right? They only define the dictionary.

Rich

So clearly every actually they're not they're not really even defined in the dictionary.

Adam

No, no, I know, but in principle they define the dictionary, but it's all just circular definitions according to dictionary sellers that are defined in it. Okay, but but but so clearly we should include the dictionary entry for every word we say every time we say it. That's great for a language learner, but for somebody who gains proficiency in the language, you don't want to log a dictionary with you all the time. And I don't need this anymore. At some point, you have to stand on your own feet, you have to can't just define everything from basics all the time. Um, what was that that talk by Guy Steele? Um where he starts off his talk, yeah, growing a language, right? Yeah, it's it's painful if you were to start every talk, every paper, everything you do, every product growing things, everything from like some bare bones vocabulary. We make an assumption about the reader.

Rich

It's a fair point, and it might be I'm just uh slightly I just haven't still haven't grown over my bias of uh against the maybe it's just the the glyph that's used for a top uh or something.

Adam

That is an unfortunate pairing that makes it look noisy and and stuff.

Rich

Uh yes.

Conor

Well, you know, maybe I should maybe this is an experiment I should do is force myself to I th I think the the interesting thing is that like I also agree that like this is a bit noisy, but my thought is not that like tacit is the problem. My thought is that like wouldn't it be great if there was a glyph for uh you know the uh upper triangular matrix. Um, you know, so if you could just if there was a uh a higher order function or an operator that if you passed it less, it would give you that matrix, and then like it completely collapses like six glyphs into one. And and also two, we're technically repeating the prefix. So like I'm not saying there should be a glyph for is prefix, but like my my thought is is there a way to like contort this in order to only have those three glyphs once?

Rich

Um uh Marshall's what is a primitive uh post, his document in BQN, because that's kind of what you're speaking to there.

Conor

Is well, I mean, I I find myself liking Tiny Apple when I'm just like solving these trivial problems the most, because like whenever you want a glyph, it's usually there. And I don't actually think tiny apple has a upper triangular um matrix glyph.

Adam

Um, but I was a notation had that if I remember right. Did it? Uh yeah we go, let's bring it back.

Conor

Let's make APL great great again.

Adam

Make APL glyph again. Um I if I remember right, it had like these I mean clearly, yeah. I mean symbols that was there were like little squares with dots in the corners and slashes.

Rich

Um it's a fairly common technique, right? Uh in APL lands. Look at this over here.

Adam

Maybe I should open up just this frame here. Oh, special indices. Yeah. Hell yeah. And we find that is the Unicode upper no, I'm not sure if they had that, but here uh I found the upper right. Look at this. So these upper left triangle, upper right triangle, lower left, lower right. And if I remember right, there are a bunch more that are uh defined that like if there's a slash going through them, then it includes the diagonal. That's amazing. Madeline, get on it. There's there's the glyphs.

Conor

But that's the thing, is like I I think so often, like the you know, optimal or ideal solution in in array languages is so strongly informed by the glyphs that you have access to. Like, and like that sounds like an obvious statement, but when you're switching between array languages and you know it takes four or five glyphs to spell something versus a single glyph, like and then potentially there's a two-glyph way to spell it in uh the language where it was five or six to spell that uh thing that was a glyph, like that that affects like the way I want to spell something, especially if like performance is not a concern, right?

Rich

Well, I was gonna ask Adam with the longest APL experience about the time before key, which is before I even joined dialogue or knew anything about APL. Yeah. But considering what it is and and what it does and how it's used, it is one of those things that boggles the mind a little bit that that people would do things before and else what before key. People did things before nested arrays, yeah.

Adam

Yeah, so uh out of product, yes, but reluctantly because this performance would be obvious dangerous, right? So you want to do whatever you can to avoid that.

Rich

But writing um and what everyone would just walk around with a little uh group bar operator or something they would use?

Adam

Not necessarily, but I think there were for things that were that were critical, people would write some bespoke code, right? So even now key has performance issues in the general case, but in certain specific cases it's good, and that sort of comes back to the same thing. If you know what exactly your problem is, you can write some bespoke code that's really uh really good and fast and simpler than what it needs to be in general. Uh so I think people did that more, and the same thing goes to the the the Boolean techniques, right?

Rich

You can now we have fancy things like pairwise application and uh and we can right that always gets me in the introductory APL tutorials uh in a in a good number of them, it introduces uh pairwise difference as a one drop minus the neg one drop. Even though for quite a while pairwise difference as a windowed reduction has existed. Yeah. And yet they always still seem to introduce it that way. I guess because that's what you see in real code. Yeah, yeah.

Adam

I think that's true. Uh I think that's a lot of it's just legacy that and and the pairwise thing wasn't introduced until later, so people just get stuck with that. Um I mean dialogue has had tally since version 14, together with key. Nevertheless, people write the first of the shape all the time, or even one pick shape. Uh creatures. Yeah, people tend it works, right? It doesn't if mostly yeah, it doesn't even really cost. I think I think yeah, people wrote up more bespoke code like this. There's a comment here in the in the chat saying spelling things with more clips can give you insight into the implementation of algorithms. Yes, I think that's true. Like how we wrote earlier um each in terms of rank and open as a good disclose and and in-close, I think gives you more insight into what's actually happening. I think it's a good thing to try to model a model more complicated primitives in terms of simpler primitives to get insight into the case.

Rich

There's a good post by Roger Huey about um the inner product and the rank operator, and doing a certain spelling of inner product using reductions and the rank operator uh gave him a a way to implement in C that was better than what they'd been doing before.

Adam

Oh interesting.

Rich

I wonder if I can dig that up somewhere.

Adam

Yeah, I think you can also you can also understand some of the notation better. So a lot of these newer APLs have rationalized their the outer product to be a monetic operator. But there's a reason why it looks like it's a dyadic operator with some weird uh left operand, and that's because you can there's actually a relationship between outer product and inner product. Um if we if we took um one, two, three plus the times uh ten, twenty, thirty, you got 140. And so this is one times ten plus two times twenty, just three times thirty, and then add it together. But so the outer product, like this, you can actually see it here. So one times ten, two times twenty, three times thirty. So if we apply the diagonal, which we can do in this case it's not really important what the diagonal is, but this is the diagonal, and then we sum it. Okay, so the inner product plus the times is the plus function applied over the diagonal, uh is the the plus function reduced over the diagonals of this outer product. And if we don't do that part, then obviously we get the outer product. So let's let's write a model sort of for of the of the outer uh of not of the outer or inner product, but of the dot so we're going to write it so we can define later what actually the outer product does, but let's just say that that is a um a given thing. So we have the outer is alpha alpha alpha uh alpha alpha omega, right? And then we check, uh sorry, that's wrong, it's the right upper end. And then we check if um some null function is equal. So let's just use zero for now. So if zero and matches, or we can even say just look at the name class, right? So it's forward equal a tx of alpha alpha. So so this gives us the name class, which let's say is going to be three if it's a function, it's two if it's an array, so if uh if it's two, so if it's a zero or any other value actually, then we just return outer. Otherwise, we do, and this will only work on matrices, but it doesn't really matter. Uh we do the left function reduction over the uh diagonal of outer. Okay, so now we can write one, two, three, z and then zero uh yeah, that's fine actually. Dot times 10 20 30 is the outer product, and the inner product is this. So if we see the zero here as a sort of null function, meaning if you try to if you have an operation called the reduce over diagonal, so you do an alpha alpha reduce over diagonal, but alpha alpha is a null function, so we do a null reduce over diagonal, that means don't actually do any reducing over diagonal, then we just get the outer product. So we so originally jot wasn't used as bind and uh and the composition at all, it was only for this. So jot was it was even called nil, I think. So it was just a nil dot times. Meaning don't do that reduction over the diagonal thing, skip that step. It's a placeholder for a null function, and now they're consistent, right? Like now it makes sense. If you have a null null function, then you don't do it. And there were there were this concept would later um extend it to other operators as well, but never they never found them their way into uh mainstream APL, including dialogue APL. So, for example, we have the power operator, which keeps applying a function until something holds true, usually a fixed point, but it could be anything, right? It could be a greater than, could be something, something external, some custom tests on on the successive iterations. So until this condition holds true. And if you use the nil function, then it's forever. So that's the fixed point, I think. Or we could you say it's it's has a number, you do it five times, right? But nil means just keep going forever. Um that wasn't implemented because it has an option for fixed point, yeah. This yeah, this was how you you write it. Um I think it didn't even have a function, I think it was just originally a number and then and then fixed point. And that just means there's no particular number. It's not even infinity, isn't really true either. That's what J uses, but it's not infinite times, it's until it's stable. It's until until it doesn't make a difference anymore. And I think there were there were other ideas for very for operators having slots unoccupied in uh so I can't quite think of what they would be, but I think we could look them up. So sometimes I think comp decomposing things into simpler primitives could sort of give you insights about how things work, how they're connected to each other. And if you replace that out-of-product notation with some other notation, just another operator, then you lose the connection between inner and outer product. There's a reason why they're named like that, inner and outer product, because they're really related. They're both products of a sort. Anyway, we did we look we didn't even look at other ways of solving this. Because now we did the the the beginning and end thing. We another way we could we we did it with the find. Another way we could do it is uh taking a prefix of a length, but uh it still get pretty dirty. We still have a ray here, so we still need an an outer product, but then we still need the masking, all of that we still need uh in principle we could do something like we could get the we could we can save on the computation by by computing the the combinations uh combinations table um and then only applying those. So I think we have got um what's cmat? C mat three. Oh that's all right. Do you also have three isn't hanging out?

Rich

No, you're right. It is a number. Oh, um, no, C mat's dyadic. P mat is the one addict one.

Adam

Oh, because we want to we want to take okay, we want to do how many ways we can be two two two out of two out of three. Yeah, okay. So it's it's the same syntax as the exclamation part, right? That's yeah, that's counting how many they are, and this one is telling you what they are. Right. So these are all the ones we need to test. And so if we got array over here, there are only four, and we need to choose two at a time. So these are all the different combinations we need to test. But that's not really we do need the ordering as long as they're unique, right? Because it could be one or the other. So I think actually we need PMAT permutations.

Rich

Uh but that only gives us Yeah, I think I was playing with something to generate combinations of things. And no, yeah, exactly. I only could basically need to do like a both. You want all the permutations.

Adam

Yeah, this is where we need we need NARS 2000's uh double exclamation point uh operator that allows you to specify exactly yeah, it has like it has like a compound operand or something that allows you to say, like, do you put the balls back again after you use them? And does the ordering matter? And all those there's like the six-fold way or some uh of of doing things twelve fold, I can't remember how it is. Um but we I mean we could do this and it's reverse, right? That just makes sense.

Rich

I mean, in the case of two and four, that is definitely sufficient. In general, you do uh you take your C Mat and then you get the P mat of that length, and then you do a uh basically a row wise out a product where you take all of the combinations, and then you're probably gonna do get a bunch of duplicates as a result of that. But why can't we just end? Why can't we just do this? No, in this case you can just do this because there's only two. But in general, oh that's what you mean. Yeah, the reverse.

Adam

In our case, there will only ever be two, right? Exactly, yeah. So these these are all the different possibilities, and there can't be any uh any duplicates because cmet doesn't care about the ordering, so therefore they'll always be sorted, and then no they never know overlap with themselves. So these are all the ones we need to check. Okay, so now if we take array and do this, so these are all the uh the pairs that we need to check, and then we just need we we don't have our function anymore, but we can just define that, right? So we can say the the prefix and uh the suffix, and we just need to check whether that's the case for each one of them, and then we ask, are there any? You still with me, Connor?

Conor

Yeah, yeah, I'm still here. Just watching and join, you know. So we can write this Monday night football except I don't watch football, I watch people coding APL.

Adam

Here we go. So this uh we think we have the problem of the duplicates though. Like if we say ab and ab. Oh no.

Rich

Uh no, because why? Because the C M doesn't give you with itself. Yeah, there's no duplicate indices in the in that matrix, is there? There's no one, two. This doesn't care, right? So yeah, it doesn't give you one, one, and two, two.

Adam

No, but why doesn't this oh we don't know because we want to count them, that's the problem. That's my mistake here. Oh, right. I did an R. Yeah, so this will give us this will give us two. So we need to do uh unique first. Oh, sorry. Yeah, yeah, I'm catching up. Um which I guess we can do that on the well, there will never be any duplicates in here, and we don't know what there are. We need to sort of take away the you take the uniques before we even start, right? So I think we can just do that. Did I make a mistake here?

Rich

Yeah, they don't have an example, do they, where it's there are different ones, but two of them are the same.

Adam

What what mistake did I make here? F what you excuse two. And if I do this, we get a nonsense result. Uh let's look at that. What's actually happening here? Maybe maybe CMET is not happy when it's one, there's only one.

Rich

Oh, it's not, it's yeah, it's a stranding. You gotta include simple as well, do you?

Adam

No, that should be fine.

Rich

Oh, that's the problem.

Adam

How do you take two? From one. From one. Oh well. That's the problem. So I mean we could just throw in the unique here. It's slightly wasteful, but too bad. Which means we can also throw the unique in in so we don't have to compare the values themselves, we can compare in here. So what actually happens here? Two, one, and what's the problem is that they are the same. Yeah, but the indice, the CMAP doesn't tell you that.

Rich

Yeah, the C no, they're not. It doesn't know. It doesn't know. Oh, so you do have to do it outside this actually. Yeah, I think so. Apply the unique to the indices, yeah.

Adam

Okay, so this is another solution that's sort of sort of neat. Get rid of that here. But of course, it relies on a bunch of code in the CMAP. Yeah, yeah. I was gonna say it's kind of big fat dependency on a big fat loopy unless it's yeah, dependent. Looks like they're any loops, but they are because we'd actually taken this giant function and uh actually it's this one, I think, and reducing over a whole bunch of things. So that's actually just it, it's iterative. But it might still be I will still be faster, I believe. Well, it's because it's not doing an outer product.

Rich

Yeah. Well, yeah, I think there's going to be a crossover. There'll be a point there. Early on, the outer product is probably gonna be just because that's optimized.

Adam

Yeah, because we couldn't, by the way, if we go back all the way, uh it's a long way, it wouldn't matter here. But the omnifix, we did we did a single outer product with omnifix, but we could actually break out the outer product into these two. So if we take our whole solution here, uh it's not going to be shorter, but it might be slightly easier to understand if you do it like this. We gotta get a JX butt on here.

Rich

Let me see the comment. Do you know about outfix?

Conor

Yeah, Oracle's mentioning uh J's outfix is useful for this pattern where you want to ignore self-comparisons.

Adam

Uh yeah, didn't we? We had such a problem once upon a time on the ray cast where we looked at uh the sum of the array except for every element. We also want to ignore itself. Anyway, so so this is another another formulation that's I can exactly fit. We sort of make smaller outer products. These are all the suffixes, and these are all the prefixes, and this is the top right uh triangle, and this is summation step by step. Also, here you said that writing things testedly requires greater discipline to keep your codes um digestible. So, what is Chase Chase outfix?

Conor

And just a heads up, I have to leave it five minutes from now, so we gotta hard stop them. But yeah, maybe the last thing we can do is look at the well, like we mentioned at the beginning, we're looking to build out our panel. So hopefully we will be adding uh a J.

Adam

Infix dependent X. So yeah, we want the outer the outer two, but I don't yeah, this sort of thing, but I'm not really sure how how you'd use it like this. It's not not really my word. So what was uh array we had over here? Uh well let's say an example full solution of sorts is it's J, so it won't win any brevity always in here. But I'm not sure I'm not sure what to write because like the okay, so we want two, but I'm not even sure what the negative thing is.

Conor

Uh uh success representative one is for like sliding window and one is for chunks. Oh yeah.

Adam

But how does that how does that help us here? I mean it no, this is infix. This is not outfix, right? There's all the okay, so we got something here in the chat. Let's do this in the array. Okay, I see. So it's just for the pairing, right? So it's using this thing that we had before with the outfix, all the all the means with single element removed, right? That's what it's using here. And then we are pairing them up, but we still need to go for each one of them and check whether they are prefixes and suffixes. This doesn't solve the even though it's called outfix, it doesn't actually solve solve the problem of prefixes and outfixes.

Rich

This just sharing issue. Yeah, of getting the combinations without the self-combination. Oh, there's an array.

Adam

No, that got eaten somehow. If you go post it on uh Yeah, I can't I can't see their butt the people that's the annoying thing in YouTube that it doesn't tell people when their message got rejected, it just silently eats them for you unless you see them, but nobody else can see it.

Conor

So yeah, if you add the link here, Adam can go post it.

Adam

Yeah, but it might take time to do that. You have to do a PR, no?

Conor

No, no, it's just a comment.

Adam

Oh, it's a comment there.

Conor

Okay. No, you just have to see F5. Hopefully it happens in the next 120 seconds. Otherwise, I'm pulling the plug on the stream.

Adam

I just had a lean on F5.

Conor

Or if I if if I had a uh what do you call it? Uh uh if I was like Big Brother, I could I could uh have some dashboard that shows all the links being created on a Ray box, but unfortunately I I don't have that, so it's not there.

Adam

I mean with uh I there might be clear I oh it has fine, so we can actually do the same thing. J has fine. Sure, can you do it in 30 seconds? No, but I can show the I can show the principle. I think it's called like E dot. So if we say uh AB and then they will find it there, right? That thing. And then we need the first of that, etc. Right, and so that will be the same thing, it's exactly like it's just translation character of a character, basically, of the of the APL code. So we'll leave it as an exercise to the viewer, uh, to figure out how that how to do that. Okay, Connor? All right.

Conor

Yeah, uh, I I think someone did just post. I guess maybe there's a hack that if you uh there's this like what looks like a Mandarin symbol for when, which is language. Um if you put something like that, uh, it enables you to to like post the array language. I don't know what that hack is, but or or maybe maybe we can see it, but the other users can't see it. I'm not seeing it, so oh there we we got something. Oh, I see. So it says there's a J1 liner shows up afterwards if you choose show all messages in the chat filter. Uh all right. Well, we'll figure that out. Maybe there's a setting on these live streams where I can just say allow all spam and uh yeah, so depending on this okay.

Adam

So here we have the the finding thing, and this is uh an or. Oh, yeah, I'm not sure whether we do a first there, but okay. Oh yeah, it's just finding if there's a I think I don't think this is right, but I'm not entirely sure. Because this looks to me like it's an an or reduction atop this, and I think it has to be a first of that instead. That's my my feeling at least.

Conor

All right, well, in the future we'll have a J Pro, and so we'll never find ourselves in this J pickle. And uh as we mentioned at the top, reach out to us at uh contact at array c uh array cast. Boy, oh boy. Yeah, I guess you have to do it for a hundred episodes before you can nail it like Bob did every time. Contact at raycast.com and we'll be monitoring uh yeah, looking for your guys' emails.

Adam

And with that, we will say crushed it.