Transcript

Transcript prepared by Bob Therriault, Igor Kim and
Sanjay Cherian


Show Notes

00:00:00 [Stephen Taylor]

In the Iverson College meetings, we always had space for one or two non-array programmers who are interested in the field, wanted to see what was going on. There was a woman with us that year from Sweden, I think, a Python programmer. She asked Arthur, "Would this code not be better if you use long descriptive names for your variables?" The answer she got from Arthur was an immediate and characteristically laconic, "No." And he just moved on.

[MUSIC]

00:00:40 [Conor Hoekstra]

Welcome to episode 71 of ArrayCast. I'm your host, Conor, and today with us we've got our four panelists. We're going to go around and do brief introductions and then have a couple announcements, and then we will get to today's topic. So first we'll go to Bob, then to Stephen, then to Marshall, and then to Adám.

00:00:53 [Bob Therriault]

Hello, I'm Bob Therriault, and I am a J enthusiast.

00:00:58 [ST]

Hello, I'm Stephen Taylor, and I'm enthusiastic about APL and q.

00:01:04 [Adám Brudzewsky]

I'm Adám Budzewsky, and I've been doing APL all my life, and I'm still enthusiastic about it.

00:01:09 [Marshall Lochbaum]

I'm Marshall Lochbaum, I started as a J programmer, I worked at Dyalog, now I work on BQN, and I'm also enthusiastic about Singeli.

00:01:17 [CH]

And as mentioned before, my name's Conor. I am a polyglot programmer and enthusiastic as well about all the Array languages. Didn't create any of them, but that's okay. We can still be enthusiastic about Array languages without writing one. And we're going to get to a couple announcements first, so I think we'll go to Adám, who's got two, and then we'll go to Stephen, who's got one after that.

00:01:33 [AB]

Okay, so whether you're already enthusiastic about APL and Array programming, or maybe not yet, I'd recommend the APL Seeds 24 event, [01] which is happening on March 27. As opposed to previous years, we're doing now a little bit longer form, where we have a panel of people discussing various things. So, if you're just curious about APL, or Array programming, which you probably are if you're listening to this, or even if you're just getting started, and want some pointers and some ideas and insights, come to that. Also, if you are new to this whole thing, then you might want to compete a bit, or maybe even earn some money on this. On February 1st, we are planning on launching what we call the APL Challenge. So, previous years, Dyalog have been having something called the APL Problem Solving Competition, and that's been morphed into a four times a year competition challenge called the APL Challenge. And it's going to be geared towards people who are new to APL. It's going to be relatively easy problems to solve. So, join that.

00:02:50 [CH]

Awesome. Links will be in the description or the show notes. And I think that leaves us with one announcement coming from Stephen.

00:02:55 [ST]

Some of you will remember that last year, I drafted a new textbook for q, which focused on vector programming in q. You can get a great deal done in KDB without knowing a lot about q. It's one of its virtues. But if you really want to understand the language, it was difficult to know where to go. So, the book attempted to address this and usher you into the ways of vector thinking in q. Following discussions in New York last year with Arthur Whitney, Nick Psaris and other luminaries, this has morphed into a community web project. There's now a small team working on it, writing content and a few students testing the exercises. We're picking up some momentum on this and we could now take on a few more students. If you're interested in this, if you'd like to get a preview, if you'd like to get a head start, if you're someone who's using q and would like to know more thoroughly, please contact me, sjt@5jt.com. It'll be in the show notes. You can also find this project at q201.org.

00:04:17 [CH]

q201.org. All right. Well, we will make sure to put both your email, the link you just mentioned, everything will be in the show notes. Very exciting that there's now, kind of seems Marvel-esque, you know, it started off with one, now you're putting a team together. And it will be very exciting to see the result of all this work when it is finalized. But yes, if you are interested in getting involved, check out the show notes for links to either contacting Stephen or going to that link. And I think that is all the announcements out of the way. Today's topic, very exciting, we love it. It's Tacit Number Six. Probably that's going to be in the title. So the surprise has already been ruined or not ruined. Is it ruined? We don't know.

00:04:55 [ML]

And it would be better left unsaid.

00:04:59 [CH]

But I mean, before we get to that, we were chatting right before this episode, the recording started. And Adám had asked me what my, should an announcement be what my current favorite language is? Because over the last two to three months, I've been releasing videos. First, it started with Uiua. Then I think the Jelly Livestream happened. And I can't remember if I ever actually said that Uiua was my favorite language. I think I said it might be. Whoever is listening to this, I'm sure someone knows. Let us know via email or on Twitter. But to wrap up, what's my current favorite language? I think it's BQN. And Jelly, depending on the problem that I, you know, back and forth on GitHub, we determined that strings are kind of broken in Jelly, or at least in the interface that Adám put together and also sort of my tool, that the way that you feed strings to the executable can get mixed up with them somehow. So if strings don't work, you can't really be your favorite language, you know? So that's why BQN, you know, is in first place. We still love Uiua. Uiua's number three. Uiua is like a solid number three, because right now it's kind of toggling between BQN and Jelly. And we should, I mean, I'm not sure if we're ever going to get the Jelly individual on, but maybe we should dedicate an episode to Jelly at some point. I mean, we're actually going to talk about it a lot today. So anyways, perfect transition. But I'll pause if there's any comments from, I mean, we've got the creator of BQN with us. Any, Adám's got a response. You know, what say the panelists?

00:06:25 [ML]

Jelly individual is a very poor superhero name.

00:06:29 [BT]

Well, actually his actual name is Dennis Mitchell, right?

00:06:33 [AB]

No, that's not his actual name. That's his online name.

00:06:37 [BT]

Ohh, that's his online name. I was gonna say cause Dennis Mitchell is the actual name of Dennis the Menace? The cartoon character? Yeah.

00:06:44 [CH]

I had no idea. I just assumed it was his name because it sounded like an actual name. I assume when I hear something like Dzaima, that Dzaima is not the individual's actual name. But hey, you know, it could be.

00:06:55 [ML]

It's not.

00:06:56 [CH]

What were you going to say, though, Adám?

00:07:04 [AB]

Well, it's a nice segue into what I was going to say. Maybe we should have a look at, or at least consider when deciding our favorite languages, what is the purpose of the language, right? Not every programming language is a good fit for every task that's out there. You don't want to do systems programming in any of these array languages. Probably want to be using C or C++ or something like that for that instead.

00:07:18 [ML]

Singeli.

00:07:21 [AB]

Or Singeli. And Jelly is a code golf language. The reason you're having trouble with the strings is because strings have very low information density. So Jelly implements string compression, literals. You would never want to spell a string out in full so that it's human readable if you want to keep things as short as possible. So it has this whole system with dictionaries and other types of compression, I think. So that you can just look up which word from the dictionary is you want. And also there are problems with input and output. Right. Jelly will never be something you would want to write an application in. It just can't.

00:08:05 [CH]

I guess, yeah, defining what is favorite language, that's important. But I should say, when I say Jelly, what I really mean is Jello, [02] which is my little wrapper around Jelly that I cautiously say unobfuscates the Jelly code. Because I mean it's not too far off from APLs and Js and I guess q has words. So q is good to go. But yeah, Uiua and BQNs. But I think it's a real shame that Jelly is a quote unquote code golf language. Because some of the ideas inside of Jelly that I have not found anywhere else, I think are, whether or not they're brilliant or not, they're very, very interesting. And we're going to chat about them today.

00:08:46 [BT]

So does that mean that your second favorite language is actually Jello?

00:08:51 [CH]

I mean, I say Jelly because like Jello is not really a language. Jello is just a wrapper around Jelly that key wordifies these atoms that I don't know how to read. So really it is Jelly in essence. It's like q but for Jelly. Exactly. And I would love to see like a wordified -- I would love to see Jello expanded past just like a tool that wraps around the language. But actually like converts. Like it would be very easy to go through, change the Jelly source code to use key words and spaces I think. And then make some changes because I don't understand the full language. But they have a lot of like links and things that refer back to previous lines and stuff like that. If you kind of got rid of that stuff and just added more like assigning to local variables and added some non-tacit stuff, I think you'd have like -- because one of the beautiful things about Jelly is that there's such a rich like set of algorithms. Like there's no language I've ever seen that has like a richer set of algorithms because there's just so many of them. Like a whole part of Jelly is that they've just kept on adding things for the sake of code golf. So they have like -- they've got a primitive for run length and code. Like it's one primitive for run length and code. And like what language do you know that has that as a primitive or a keyword, let alone in the standard library? Like very few languages have run length and code as something that ships in the standard library. Because it's useful, but is it so useful that it belongs in a standard library? Whereas in Jelly like it's a single -- I guess not a single keystroke, but whatever. Two keystrokes and then it shows up as a single character. That is pretty phenomenal if you ask me.

00:10:28 [AB]

Well, I mean, Heretic?

00:10:31 [CH]

What's Heretic?

00:10:32 [AB]

You are.

00:10:34 [CH]

I'm a Heretic?

00:10:36 [AB]

I mean, what's next? You want to keywordify APL and BQN and Uiua as well? Uiua allows you an input method like that, but now you're saying that you'd rather have words and spaces between them than having symbols that are mnemonic for what it does?

00:10:48 [CH]

Well, I mean, this is an interesting question. Yes, I am not totally sure what actually I think is the best. Is it the q keyword model or is it the APL/BQN Unicode symbol model? And Uiua, I guess. And then J you can actually put in a third category of like spellable via the keyboard, via digraphs, trigraphs, and single ASCII characters. And k are close to that.

00:11:19 [AB]

And there's a level in between where commonly used things are using symbols, right? There are almost no programming languages that are entirely words and no symbols.

00:11:34 [CH]

Yeah. And I know so Joao, a former interviewee on this podcast, he made the argument that really like the space for these is like a tool of thought. Like you're -- and like in the space of these tools, like the markdown tools where you can jot down notes and stuff. And like every once in a while now I will jump -- instead of using Bash, I will jump into the BQN editor, hit the, you know, system button, files.lines, read in a file, and then start messing around that way. Because I can be more productive that way than I can be with Bash. I actually tried to do it once when really what I just wanted was grep and then I realized why am I trying to grep stuff like not using grep? That's what grep was for. Don't try and replace grep with BQN. There's a tool -- use the tool that it's used for. But I was trying to analyze some compile time error messages that I had saved into a file and then I wanted to know how many lines were there, what was the distribution of the length of the lines. And then that's like four characters in BQN. Like once you've read the file in, it's just your mapping like count over the number of, you know, the nested list. So it's like length each and then you can -- anyways, you can mess around super quickly. I think that's like it's amazing for that. But the other day I was solving some problem and the end result in BQN, like I actually liked it better in Jello because it was using like SQ for square instead of multiply self. And when I was building up like a monadic fork, it was -- anyways, I flip flop between are symbols the best or are keywords the best? I don't actually know. I think at times there's like I lean towards one or the other. So when you say heretic, you're totally correct because I think that like the epitome of beauty in like these single liners and Kedane's algorithm is definitely like the APL and the BQN symbols. But for larger problems, I think sometimes like the readability becomes harder when you are staring at a sequence of these symbols versus if you have like short names for them. Thoughts, comments? I mean, we're totally -- we'll get to TACIT 6 in a second, folks. But --

00:13:49 [BT]

Right now we're on Conor designs a language.

00:13:51 [ML]

Yeah, well, I really wish there was more exploration of keyword-based array programming. I mean, I guess Nial [03] does a little of that maybe and q, of course. But for the most part, it doesn't feel like anybody's really looked into like what other choices can you make when you decide to go with keywords instead of symbols as opposed to just saying, well, I want array programming, but I don't like the symbols, so I'm going to replace some of them with keywords. I guess Ivy is another one that uses more words for some things.

00:14:24 [BT]

Well, and J has keywords, but it's more for sort of more procedural type stuff. So you can do it, and it's got the keywords.

00:14:33 [ML]

Like control structures.

00:14:35 [AB]

Okay, but then so does APL. And you could even say -- where do you draw the limits on the language? BQN and APL both have the system functions or whatever you want to call it. Are those keyword built-ins? There's no real distinction in APL, at least, between a primitive and a system function. They're just different spellings.

00:15:07 [ML]

Yeah, well, I mean, I try to not implement the things that you would implement as primitives in BQN system functions for the most part, just because -- like you should be doing those with primitives. And then you don't have to worry about, you know, is the particular BQN you're using going to support this system function, stuff like that.

00:15:29 [AB]

Right, whereas in APL, for various historical reasons, it's very blurry, even within a single thing. When people speak about this, like I speak for Morten, our CTO, what's the core language? And it says the glyphs, the primitives. But we even have a synonym. We have the I-beam symbol, which provides system services. It's almost like a contradiction of itself, right? It provides system services, but it's a primitive, not a system thing. Why is it not a quad system service, or something like that? But it also comes into -- because APL functions only take a left and right argument, sometimes you want named arguments. And so we have this a bit special operator called variant. It looks like a quad with a colon inside. And it allows you to give name/value pairs as right operand, and it modifies a system function, which is its left operand, to behave in a slightly different way. But syntactically speaking, it's just a normal dyadic operator. It's about the most systemy operator it could possibly be. It doesn't apply to primitives at all. You can't use it for anything you define yourself. It's only for system things. But it's a primitive with a symbol. And it happens to have a synonym, which is quad OPT. So you have the exact same built-in that is both a keyword and a symbol. Clearly the line is very blurred here.

00:17:00 [BT]

Well, an example I can think of in J is you've got things like, well, if, the if do else thing. But you can do the same thing just using the power function and binary arguments.

00:17:11 [AB]

But that's not the same though you can you can accomplish the same.

00:17:15 [ML]

Yeah, well, you have to pass in an argument then. So the syntax ends up being very different.

00:17:20 [BT]

Yes. And that's what I see is the difference. You end up accomplishing the same thing with the syntax that people might be a bit more comfortable with traditional programming language.

00:17:28 [ST]

Well, here's a way of thinking about the keyword versus symbol question. So you start at the opposite end with the most familiar of symbols, the plus sign. And my question is, why do we not want that to be a keyword? Because the reasons why we would not want that might be, you might find, illuminating.

00:17:51 [AB]

Could you imagine, Conor, when you're writing C++, you had to write PLUS space PLUS space I to increment your.

00:18:00 [CH]

I mean, it's actually not that far of a stretch because when we have to pass a function object to an algorithm, you can build up a lambda or you can call the std colon colon PLUS brace brace. That's how you pass it, which I mean, I've seen in Swift, I believe, that when you're passing a binary operator to a function like reduce or I think they have a scan, but it's in an algorithms library and they call it reductions, which they might have borrowed that from closure. But they are able to just pass like PLUS, like in your argument list, you can go whatever comma and then PLUS. I think, you know, if there's a Swift programmer like listening, I'm sure there's some language where you can do that, though. And like that would be beautiful.

00:18:41 [ML]

There is, I know.

00:18:42 [AB]

Is it Singeli?

00:18:44 [ML]

Yeah, you can do it in Singeli. The one thing about that is that every operator you can give two definitions, you can have the infix and the prefix definition. So if they're both, Singeli just chooses the infix and then you can't use the prefix one. So like minus, you can pass the subtraction function, but you can't pass negation.

00:19:08 [CH]

Right.

00:19:09 [ML]

So it's like without, I mean, you can, every operator is just a cover for a built in. So you can pass the built in, but you can't pass it as its operator spelling.

00:19:18 [CH]

And to, you know, respond to what you said, Stephen, is I think that's like a very, very like thought provocative remark. It's like, why? Because no one really is going to say, I want to write a prefix version of PLUS parentheses, you know, one comma two and parentheses. Everyone wants the infix version. And why is that? That's because everyone since like, what is it, grade two, grade three, like is taught around the globe that that's what addition is. Like even if you're not a huge fan of math and you don't think you were that great at it or whatever, you know, whatever your history with mathematics is, everyone knows what that does. And like it's because we learned it so early. It's second nature. We don't even think about it. And if you then by --

00:20:02 [AB]

I don't think it's just that. I think it's also to do with how we think about things and how we speak about things, because you also speak like that. We choose a notation, a written language that matches how we speak.

00:20:14 [CH]

But that just is speaking to the fixity of it, prefix versus infix. I think what we're focusing on here is symbol versus keyword. Like right there, then it says, okay, well, why would you not prefer one space PLUS space two? Like that's what you just argued for, which like I agree. Like it -- I think maybe it matches a little bit closer, but honestly, like I have never had the aversion to LISPs, [04] like where it's prefix. Like for me, it's just a calling notation. Like in fact, I think that there's something very, very nice about the LISP system that everything is prefix. We don't -- like I think it's actually odd, and this is -- we're skipping ahead to the part where I do a little monologue on the different composition strategies, where like if you think about a normal, quote/unquote normal popular languages, like what are the ways to apply functions? Most commonly, your languages use parentheses to apply a function. But then -- so that's just your regular like prefix function application. But then most languages also have these infix operators that people don't even really think about as quote/unquote function application, because there are these different things that aren't called functions, they're called operators. And depending on the language, these operators have some like crazy nested precedence of pedmass or bedmass, unless if you're Smalltalk or APL. And anyway, sorry, you're going to say something, Adám.

00:21:41 [AB]

Well, you quickly skipped over a thing. You said most languages, at least common today, use parentheses for function application, which is your simple prefix. No, no, that's not a simple prefix. That's a prefix plus indicators, two indicators that you're applying a function. There's a big difference between function argument and function begin mark of argument, end mark of argument.

00:22:10 [CH]

I don't understand.

00:22:11 [AB]

There's a big difference between fx and f open paren x close paren. So it's not just a prefix.

00:22:16 [CH]

Yeah, yeah, I understand. But like that's why -- no, no, no. But that's why I said most popular common languages. We're not talking about Forths, APLs, Haskells. We're talking about Python, C++, Java, Rust.

00:22:28 [AB]

I'm just objecting to you calling that prefix. That's not just prefix. When those languages also allow you to write minus x, that's a proper prefix.

00:22:37 [CH]

Okay. All right. So let's be more pedantic then. Prefix with parentheses versus other types of prefix. But in general, all right, let's just leave it at that. So, yeah, prefix with parentheses. And then technically I guess you could -- well, I mean, yeah, you could go on to say that then lisp is not prefix with parentheses. It's parentheses then prefix. But for me, like the order or where the parentheses go don't really matter. I think lisp is similar to Python in that all you're doing is shifting the first parentheses to be to the right of your function name than before your function name.

00:23:18 [AB]

Really? Hold on. Maybe I'm misunderstanding something. Do you need parentheses in Lisp? Yeah. I didn't think so. I thought the parentheses was just to group things. In order to apply a function, can you not just write --

00:23:29 [CH]

I'm pretty sure I'm pretty sure that's the application, is it not?

00:23:32 [ML]

Yeah, I don't think you can apply a function without parentheses.

00:23:34 [CH]

Ohh yeah that is that is the indicator of application.

00:23:38 [AB]

Gee, I got this syntax all wrong. What did I know?

00:23:41 [CH]

The original point was that Stephen asked, you know, why do we want infix plus? And then Adám replied saying, well, it matches our language. And then I replied saying, well, that really only argues for fixity. And then I started talking about the fixity of operators and how people don't really think about that as separate function application. And, like, for me, whether it was plus one two or one plus two, like that doesn't actually make -- like some people are offended by, like, the lisp prefix syntax because we're used to seeing it as infix. But for me, it doesn't make a difference. And I also think that there's something very nice about the lisp system, that, like, it's very regular. Whereas in all other languages, like, that's why I love APL because it has infix operators for all binary operations, not just plus, minus, divides, times, the ones we learned in school. And then we stopped at min and max for some arbitrary reason. And then in every other language, C++, Python, Java, when you want to spell min or max of two things, we're no longer in infix land. We then switch to prefix. And, like, what's the reason for that? Like, it just kind of seems arbitrary. Whereas in lisp, everything's the same. Like, at least they, like, they chose a lane. Like, sure, maybe they chose the wrong one for, like, infix one plus two. But at least they were like, we're going to do everything prefix, and they just stayed in that lane. Whereas every other quote, unquote popular language, they added these operators with, like, a complicated precedent system, which then requires people in order to disambiguate put a parentheses all over the place, which is why, once again, APL is nicer because there's no precedence. It's just left to right, right to left. Who cares? Anyways, circling all the way back to Stephen's question, I think it is interesting. Like, if I was as familiar with every single function or symbol in BQN or APL as I was with the plus, would I then have this, like, thought, like, oh, I kind of like this syntax better because we're using keywords, and it's easier for me to read. Maybe it is just, like, a familiarity thing that, like, this sequence of functions in BQN is a little bit harder to parse because it's more complicated, and I'd either have to split things up or shorten it somehow or add keywords. And it's like, well, if I could recognize all of these symbols as well as I recognize plus, maybe I would just see it, and I would read it like I would any Python or C++ line of code. So, like, perhaps you are correct, Stephen, is this long-winded tangent off a tangent off a tangent is that, like, or I'm not even -- you asked a question. It's not about being right or wrong. It's that, like, yeah, why do we prefer one versus the other?

00:26:03 [ST]

Let me offer a suggestion that it's a mapping issue. Conor, you said since the age of two we're familiar with the St. George's cross plus symbol. So I would say that's analogous to -- that's part of our assembly code. That is basically the way in which we think about addition. If I use the English language words add, addition, or plus, they're kind of at a remove from that, and I map them internally as a cognitive mapping onto something that I do think with. And so the plus, the plus symbol is part of my own language for thinking in. And that's not true, for example, of arc cosine. Right. I can't even remember what arc cosine does in trigonometry, but the only thing I remember of it is that if I pass it minus one as an argument, I get pi. So the q keyword, a cos, does just fine for me. I've got no lower level primitive to map that to. I'll come back to this mapping issue in a moment. I'd like to hear what Bob has to say on this.

00:27:13 [BT]

Well, what I was going to say was the situation you get into, though, with the dyadic versus monadic, the plus can have another sign depending on the number of arguments it has. Because if it's infix, it means addition. If it's, at least in J, if it's monadic, if it's prefix, then it's conjugate. And so that might be an argument with Stephen's mapping, that for prefix you might actually give it a different symbol, or you might actually just give it a couple of letters to do that, to specify it. Because otherwise, this is where you start to get into issues with tacit, is you have to know the context of your sentence before you can know what the operators are doing.

00:27:32 [CH]

Right.

00:27:52 [ST]

So k [05] tackled that by giving the monadic versions of an operator, like plus a suffixing it with a colon to indicate that you mean the monadic or unary version of it. And then q said, well, never mind all that, we'll just put in keywords and you get flip.

00:28:18 [ML]

Yeah, and one of the really nice things about this prefix with parentheses syntax is that you put all the different numbers of arguments on equal footing. So I like in infix that you have the function next to both of its arguments, but being able to, and like even in Lisp, you can do call plus on any number of arguments, which is a lot more natural than saying I have five things and I want to add them together, therefore I will order them and do a binary plus between each of them. It's much more natural to call plus on this whole list of things.

00:28:53 [AB]

Like Nial does, right?

00:28:55 [ML]

Does it? I don't remember.

00:28:58 [AB]

Nial had this system where the functions are also monadic to dyadic, but the monadic form is always just taking all the elements as arguments, so plus is sum, right?

00:29:11 [ML]

Oh, yeah. But then you can't really see from the syntax how many arguments it has, right? Because it could be dynamic.

00:29:16 [AB]

Well, maybe some functions indeed need any number of arguments and with a consistent way of behavior.

00:29:25 [ML]

Well, yeah, but I don't think that should really be the default syntax for it. It's nice if you can just tell right away.

00:29:32 [BT]

The advantage of the prefix is that you can actually always, like you always know that your operator is first and then you can read right afterwards how it's going to operate. Now the question would be if it had a single argument afterwards, is it going to behave differently than it would if it had a list of them? And then that becomes a question of how you structure your language.

00:29:54 [AB]

Well, k q, they even do some overloading like that. You force certain things to take a number of arguments and then they do something related but somewhat different depending on how many arguments you've forced down their throat, basically.

00:30:12 [ST]

Yeah, or to put it in more abstract terms, overloading by rank. Let me take us back to the symbol keyword issue because I think there's more juice in that yet. Some years ago, I wrote a paper in which I introduced, it was an APL paper, I introduced the term semantic density in programming applications. And I think the paper was called something like pair programming with the user. And it was arguing for a style of application development in which you sit alongside your end user and you write code in which the user's vocabulary is represented by functions. Point of this being APL is that all the primitives are symbols. So the user tends to ignore those and just see, in our case, the English language names of the functions we defined. So it seemed to be developing a domain-specific language using the user's own expressions. Now, the user's vocabulary for whatever the business problem is, is helpful metaphors for the programs, the functions involved. So in the user's business, they're doing this, that, and the other. And we have corresponding things in the computer system that are doing those, but they're not actually doing this, that, and the other. It's all representational stuff in bits and bytes. But using the user's own vocabulary for those functions meant that the user had a decent chance of following the program logic and could help, and we could use it to think through processes and flow and logic, which was amazingly useful because our end users, in that case, turned out not to be systems analysts who'd carefully analyzed all the logic and the workflows, but basically clerical assistants with no tertiary education and limited ability to describe or analyze what they're doing. So we really needed to have them close to the program and the logic and the development. The point of all this is that the vocabulary that they use, that we use to name programs, represented a kind of mapping. And my assertion here is that keywords in programming languages function the same way as a metaphor. So one of the disadvantages of using anything other than APL or a symbol-based language for developing using semantic density and pair programming with the user. Semantic density, by the way, was simply a metric for the proportion of your defined tokens in the program code that came direct from the user's vocabulary. If you've got 100%, the user looks at your source code and it all appears to be in language that they can understand or means something to them. So first point is, if I've got to mix that in with keywords, which belong to the programming language's own metaphor mapping then I can't do the pair programming as efficiently because I'm mixing in programming language terms with the user's own terms. And secondly, there's a subtler point here that the programming language keywords map to something which I've had to internalize. And it's better if those keywords are not fully English language words. Okay, I want to leave it at that point because I've yammered on for quite a bit and I probably need to sit with that last point.

00:34:14 [BT]

So are you putting an abstract layer over what you're doing as the person who's doing the programming and what the person sitting beside you sees is the creation of a number of functions that they understand, they'll give names to them, and they do what's expected? Would they be aware of what you're doing underneath the covers?

00:34:34 [ST]

No, they're black boxes to them. I'm talking about the domain-specific language which we expose to the end user so that we can think through the code logic together.

00:34:48 [BT]

And so on the next level up, if you're putting these functions together to say, "I want to post something, I have to do this, this, and this," the this, this, and this are the black boxes and they say, "Oh, you wouldn't do it in that order." And then that's their understanding of what's going on. They don't need to know what's inside the box.

00:35:04 [ST]

That sounds about right. Yeah. Yeah, yeah.

00:35:06 [CH]

You're gonna say something, Marshall?

00:35:07 [ML]

Yeah, so I linked in the chat a page that I wrote about the symbol versus word question. [06] And I described the difference between symbols and words. And one of the sort of themes about that is that there are many more possibilities for words, and many of them are subtle. So, you know, some words are subtly different. And so I kind of came to the conclusion that when you use a symbol, it's sort of a suggestion from the programming language to think of this thing that's being symbolized as a basic concept, or of course you might say a primitive, as something that's not, that, you know, could be in any language. That is, it's just a tool for you to think with that's not connected to any particular domain, as opposed to something, you know, that's specifically made for one purpose. And this is one reason why I don't have a lot of things in BQN, like string splitting, you have to compose with multiple primitives. There's no matrix multiplication, because a lot of these things I think of are not really individual primitives. They're, you know, patterns that you might have, but they're not fundamental to programming in the same way.

00:36:21 [CH]

This brings up a related but unrelated question. In my most recent YouTube video that was posted yesterday, which is a week ago now for the listener, depending on how loyal our listener currently is...

00:36:32 [ML]

For the eager listener.

00:36:41 [CH]

For the eager listener. One of my predictions for 2024 in the video was called "Top Programming Languages of 2023," and I revisited my predictions for the previous year and then made three new ones. The third one was that one or both of BQN and WeWOW were going to get recognized by GitHub as "official languages."

00:36:56 [ML]

Well, I can comment on the syntax highlighting if we want to derail ourselves. So GitHub has their tool, Linguisher, which requires you to apply for syntax highlighting. BQN is somewhere in the middle of this process. I have found the process very unpleasant, so I'm going to point out that Codeburg already supports BQN syntax highlighting. It's structured as a German nonprofit, I believe. I think it gives much better guarantees than GitHub did that it won't, you know, sell out to a big company and become like GitHub. So I strongly recommend you use Codeburg if you're able. But yeah, so we have, there is, as I mentioned, a requirement that you have a certain number of repositories with BQN code to be included. And I said, "Yeah, we're going to get enough files in the search." And I said, "Yeah, we'll get enough files in the search during advent of code." What I found during advent of code is that GitHub search does not really work at all. So there are two problems that I've identified so far, which is that first, only a fraction of repositories ever get indexed, as far as I can tell, ever. And second, of the indexed repositories, it does not actually count the number of hits correctly. So where we are is we sent a, or a BQN programmer sent a pull request for the syntax highlighting once we thought we had enough results in the search. And the GitHub employee who answers this, well, I mean, first we had errors in the pull request. And second, the GitHub employee said, "Well, you know, this repository has too many files, so I'm pulling this out."

00:38:36 [CH]

What? Too many files?

00:38:37 [ML]

I mean, they're stated to be part of their procedure.

00:38:40 [CH]

Okay.

00:38:53 [ML]

What they actually want to test is that there are 200 repositories with BQN files, which I'm very sure is the case. Because, you know, there are not as many BQN files per repository as most languages. But so they actually, they can't do this with GitHub search. So they instead check that you have 2,000 files.

00:39:00 [CH]

Oh, I was going to say, like, I swear I've got like at least five or ten repos that at least have one file with the extension .bqn. Like, does it show up in the list? Of course not, because it's not recognized. But like, I swear, like, I'm already like 5% of what you need.

00:39:14 [ML]

Yeah. So, well, so then I found all these repositories that weren't indexed. So it was like excluding this, we were at 1.8 thousand. And I said, "Okay, I'll index all these repositories." I know because I have them locally for tracking admin of code that they have, you know, 300 files in them. And then I indexed them. And this brought us up from 1.8 briefly to 2,000. And then when I refreshed the search later, like the next day, it was back down to 1.9 thousand. So clearly the count is incorrect. Because actually if you include the repository that he excluded, right now it's giving you 3.4 thousand. And this repository has like 300 files. And if you exclude it, it goes down to 1.9 thousand. So I have no idea what's going on. 300 files counts for 1,000 and a half. And when I commented earlier about all these missing repositories, what he said was the priority is fixing the tests in your pull request, not the popularity. And then so last week we fixed the test and asked, you know, can you rerun the test? Because he has to approve even running the test. He approved running the test. Test passed. No comment for the last week. So he has not once commented on the fact that search doesn't work. So yeah, go to CodeBerg. I strongly recommend using CodeBerg.

00:40:31 [CH]

And my first prediction sounds like it's going to be correct, though, if we're already only two weeks into January.

00:40:35 [ML]

Who knows?

00:40:48 [CH]

All right, folks. Well, consider hosting on CodeBerg. Sounds like GitHub, they've got some issues, but hopefully they'll resolve them. And then a side prediction, which wasn't really to do with rankings, was that one of them was going to get -- one or both was going to get a package manager. Do you think that's on the horizon? Because, like, string splitting is something that -- or, like, another thing that I think of is, like, that I miss from APL is the partition function. [07] And to spell that in BQN is definitely doable, but it takes a few primitives composed together. Whereas really I just want to be able to -- the same way that I go, you know, system function file.lines, I want to go, like, system -- or not system function, but just, like, have imported from somewhere. And the same way when I was doing Advent of Code where you just go str. -- what was it, NATs or something like that, or two NATs. Like, yeah. When it's not a primitive, but it's still something that you reach for all the time. I guess this is the whole Aaron Hsu idioms versus libraries. And I kind of want, like, my preferred thing is, like, I still want the libraries when I'm in an array language. Like, even if it's not a primitive, which is why I think I -- Jelly is so nice. Because it's, like, they have stuff that, like I said, like, even run length in code, they have a billion splitting functions. Every once in a while they don't have something I want, and then I just go add it to my version, which I forked and called Jellyfish. But it's only happened a couple times. And, yeah, it's --

00:42:00 [AB]

That's what jellyfish is. But there's already something called jellyfish. Before that. Whatever.

00:42:05 [CH]

Well, it's it'll be the battle of the jellyfishes.

00:42:07 [ML]

Yeah, there's a there's another language called jellyfish.

00:42:10 [CH]

Ohh Dun Dun Dun.

00:42:11 [ML]

I wondered if I should tell you.

00:42:13 [CH]

He found out live on episode 71. Folks, no.

00:42:17 [AB]

But, again, Jelly's purpose is being as short as possible for the commonly occurring tasks in CodeGolf challenges. That doesn't mean that the language wants to be nice in any way, or pure in any way, or make a good distinction in any way between things that are more systemy and things that are more core-languagey. It just wants to be short. That's the one purpose. And the symbols there, while they're somewhat mnemonic, they also have one criteria, that Dennis should be able to type them on his keyboard layout. And he uses US International, so everything can be typed like that. But here you're saying you want to have library, you want to have things you can reach for, things that there are some things you use all the time, reading in files and so on. So, maybe, are you saying maybe those things that you reach for all the time should be primitives, should have symbols? Not that they should be primitives.

00:43:15 [CH]

I just don't want to have to spell it. You get very specific, like the partition, I believe it's partition in APL, because there's partition and partition in Close, but I think this is the partition one, where you're given two arguments, a vector and then a Boolean vector. And you drop everything that corresponds to a zero, in the simplest case. I know that there's versions where you have one, two, three, etc. But in the simplest case where you have a Boolean vector, you drop everything that corresponds to a zero, and then you end up with a nested list of all the contiguous ones. In BQN, there's no equivalent, one-to-one equivalent of partition, so you have to do it with group. But the way that group works is different than the way that these kind of partition functions work. So, Marshall can correct me if I'm wrong, but you usually have to, on the left, compose some kind of either scan or something, and progressive index count. You have to do something that gives you a set of indices that will then give you the same result, paired with group, and a dyadic before, or something like that. So, it's still spellable, it doesn't take 20 characters, but every time I have to go and do that, I have to think about it. Unless if Marshall has some tricky thing that I just haven't realized. Or, I shouldn't say tricky.

00:44:28 [ML]

Yeah, no, there's nothing super quick. We've considered adding a system split function for that. It's split in the strings library, too.

00:44:37 [AB]

But then it's not general anymore.

00:44:39 [ML]

No, and yeah, that's one of the things, is that you don't, like...If you actually do serious tech manipulation, this one splitting function is not really enough. Or, if you try to use just that splitting, what you'll do is pre-process the string and post-process the output, and end up doing a bunch of weird stuff like that. So, it's nice to be able to know the group pattern, because it's fairly easy to tweak to get exactly what you want. But still, for basic things, it would be nice to have a way to pull out everything that's highlighted, like the Dyalog idiom does. So, a system split function would be nice for that.

00:45:18 [CH]

And my point is that, not that I want this to be a system function. It's that I would be totally fine if this was in some library that I could include some little thing. And then there's some BQN equivalent of cargo, which I know is a huge cargo being the Rust package manager, or crates.io, etc. Whether it's a system function in a library or a primitive, for me, I just don't want to have to spell it. I know what I'm reaching for, and it's so nice in APL when I can just reach for it. And to bring up another language, J, I think, honestly, the cut functions in general are some of the most interesting to compare across languages. Because so many of the languages make different choices. And J has done something incredibly powerful, but also extremely confusing, in that I consider the cut function a, what do you call it? Tetradic function. A function that takes four arguments, because it takes a operation that you can apply. So, usually, if you want to do the APL partition, you pass it in close, the less than, as the left function to cut. So, that's your first function, is like what operation do you want to do? And this is super powerful, because this does not exist. You can replace that in close. In close is the default in the APL partition. But you can replace that with, like, the count. So, if you just want to get the count of the sequences that would -- you don't actually have to do, like, a count each over your nested list. You just replace in close with the count. And that's fantastic or tally, or whatever J calls it. And then on the right, you take -- your second argument is just going to be your array. But then you have technically two more secret arguments. One of them is, like, the negative 1, negative 2, because it's either going to be a positive or a negative, which affects the behavior of whether you include the elements or you just drop them entirely. And the 1 or the 2 points to -- you're not actually -- it's not based on the 0 or what the values are. You look at either the first or the last element of your array to determine what you're splitting on. So, you've got your first function, the array, the negativity of that 1 or 2, and then whether it's a 1 or 2. And it's incredibly powerful to have all of those options. But this is basically what happens in an APL where you have, like, monadic and dyadic functions. And you're trying to get what Marshall's pointing out, is that, like, a single split function isn't enough. Sure, if what you want is to keep everything that corresponds to a 1 and drop everything that corresponds to a 0, perfect. The APL partition function is exactly what you want. But sometimes you want those other variations that J has provided you with. But now you kind of have this very cumbersome interface where you have to remember what does the negative positive 1 do and what does the 1 versus the 2 do? I never remember them. And, like, potentially it's just better to have this all in a library, all with slightly different names. And, anyways, we got -- Bob's got his hand up. It was first. Then we'll go to Adám after that. And also, the last thing I'll say is, clearly, this episode is no longer tacit number 6. It is primitives versus keywords. We will do tacit number 6 in the future, folks. Probably my fault. I shouldn't have said what my favorite language is, and then we took a hard right. But, anyways, over to you, Bob.

00:48:19 [BT]

Well, what I was going to say is rather than thinking of it as a tetradic function, cut is a conjunction. And on one side it takes a verb. On the other side it takes a noun. And that creates a verb that then works on the argument. So you can change what your two operators, your operands are to your operator, which is the cut conjunction. And then you can feed in whatever arguments you want into it, dyadic or monadic.

00:48:48 [CH]

Right. And I guess I wasn't thinking of it that way because the -1, -2 is similar to rank, but most conjunctions, in my head, take two functions, not a function and a value. But they can.

00:49:00 [BT]

They can, yeah. Exactly. But they don't have to. And if that's the case, then rank's the other one. It's a case where it doesn't have to take a verb as one of the operands. It can take a noun as an operand. Because rank is a conjunction as well.

00:49:11 [CH]

And there are examples in BQN and APL, for instance, over, aka the psi combinator, is an example of quote-unquote a tetradic function that does take two functions to start with. The one that you're going to apply to both arrays, and then the binary one that you apply afterwards, and then the two arrays as well. This one does the same thing. It's just that you don't pass two binary functions, or you don't pass two functions, period. You just one function and one array.

00:49:40 [BT]

It's that difference between a verb and a conjunction. Conjunctions take operands. Yeah. And then outside of that, that makes them into a verb or actually could be any part of speech. And then the arguments outside that monadic, whether it's infix or prefix, that's another issue. You've already created your function out of your conjunction plus whatever you've added to it.

00:50:01 [CH]

It still is a tiny bit tricky, though. So it's really not even tetradic. It is triadic. And the two Boolean arguments of one versus two and positive versus negative are squeezed in to that one array that the initial conjunction takes, which is still a little bit tricky. But it is a great point, a better way to think about it.

00:50:22 [BT]

The other one is all the trigonometric functions, the circle dot, the O dot ones. You've got this whole family of things hidden under this one little area, this one symbol. And they are kind of confusing, and they do obfuscate a bit. But when you figure out what's going on, they do make sense.

00:50:42 [CH]

Should we go to Adám, or Adám and then we'll go to Stephen?

00:50:44 [AB]

Right. So we were in the middle of discussing things like the cut primitive from J. Yeah. And so we were considering adding such a thing to Dyalog. I think it was Roger Huey that said that there's maybe a bit too much packed in under that coat there in J. And so we would add just one part of it. And that's how we got the stencil primitive. [08] Which, in my opinion, is a bit too limited in the options that it gives you. It does a very specific type of job very well. And then it doesn't really want to let you do anything else than that without major effort. But there's still design room.

00:51:25 [ML]

I believe that's because it's too complicated rather than because it's too simple.

00:51:29 [AB]

Yes and no. And there's always that question of should you just return some kind of nested list or not nested list, and then apply with an each or rank on that? Or should you take an operand and apply it as part of the operation? Right. I mean, maybe the simplest to understand is doing a scan or doing a reduction on each of the prefixes. A question. But there's the risk of trying to pack too much into things. And Bob mentioned the circle or the O dot. And, of course, the most clear offender here, but there's not much you can really do about that, is the foreign in J or the I beam in APL. It just takes a number and then that's what you get. J has more of these. And you have this, what's it called, the B dot. It's binary function number such and such, which does make sense.

00:52:27 [BT]

Yeah, and actually the other thing I was thinking is in J, most recently, the fold conjunction that was brought in, Henry did name them differently. And as a result, people, I think, are having trouble figuring out which one they want to apply. But then he did use the F dot, the F dot colon, the F dot dot and such for the different flavors in that case. But I think that might just be people not being as used to using names that way, because the rest of the language doesn't really do it that way.

00:52:58 [CH]

And Stephen, do you recall, you had a thought?

00:53:01 [ST]

Yeah, this goes back, I think, to 2014 at the Iverson College meeting that year was for a week at St. Edmund's Hall in Oxford. And Arthur Whitney was presenting k running on the bare metal. He had a project to take Linux and the operating system out from underneath the language. And I think I wrote about this in an article in which I dubbed k running straight on the metal, K its own operating system as chaos, and called the article "Kos is Coming." He presented an early version of Chaos with, I think, four desktop applications. One of them was a very simple text editor, sort of like Notepad. And he then opened it up to show us the source code, which was four lines of k with his text editor. And he stepped us through them, editing the source code and showing how the application changed as he edited the code. There was no compilation step involved. It was just all live and hands on. And in the Iverson College meetings, we always had space for one or two non-array programmers who are interested in the field, wanted to see what was going on. There was a woman with us that year from Sweden, I think, a Python programmer. And she asked Arthur, looking at all his one character names, would this code not be better and clearer if you use long descriptive names for your variables? And she got an answer reading her blog sometime later about the event. I learned that she got two answers. So the answer she got from Arthur was an immediate and characteristically laconic "no." And he just moved on. But Chris Burke apparently took her aside afterwards and explained that the reason why we array programmers didn't think the code would be better with long descriptive names. And whenever this comes up, I always think of those long variable or class names in Java, invariably written in camel case, which remind me of Friends episode titles like the one with the teddy bear. Chris explained that there was a lot going on in a line of k or APL or whatever. And we array programmers were more interested in the transformations and having short variable names let us focus on the transformations, what's going on in them. And I think this crucially points to why we like those one character symbols. I propose we're all really here because we're drawn by this very high signal to noise ratio in the array language code.

00:56:17 [CH]

Yeah, I mean, I completely agree with the signal to noise. Anytime the word "ceremony" comes up, it's like a few guests have mentioned that. Like, I completely agree with that.

00:56:28 [AB]

I mean, we're also very good, humans, I mean, are very good at quickly grasping an image, at least a simple image. Just think about how the world even is evolving around you. We use icons and stylized images of situations everywhere. When you're on the road at high speed, and you need to be told that there's a curve ahead, a little bent line with an arrow on it, compare that to writing, well, the road is going to curve up ahead, written out in letters. Or there's like this deer that's jumping in. Imagine if it said warning, deer might jump over the road up ahead, and so on and so on. Just look at whatever device you're using to listen to this podcast. They're eradicating words from the screen, replacing them with strange little symbols. And the symbols aren't even proper pictures. We prefer these stylized line drawings that kind of hint at what the functionality is. And they tend to get simpler and simpler over time until they just have the very essence of what it is about. There's clearly something in humans that fit well with this kind of language, except when they do programming. Then they like to spell things out with long names, apparently. My father did a project for a German company in APL, but the German company had some strict guidelines, code guidelines. They required the names that were being used, I guess variable names, to be in a certain format, formulated in a certain way, using certain words. They also had strict requirements on the maximum line lengths of the code, and it was impossible to solve the problem. If you can't fit two of those names in one line, there's very little you can do in APL. But why is that? I mean, you could even ask a question further. And some people, every once in a while, they get this question, "Why can I not assign to my own symbols in APL?" If symbols are so great, I should be allowed to use them by myself.

58:37 [ST]

Your point about the driving instructions, I think, is really central here. If you receive the driving instruction as a little bit of narrative, it seems to kick off some other storytelling process in the brain that's engaged by [the] English language or French (or whatever your first language is). And using symbols or even very short acronyms as variable names bypasses that and enables us somehow to go directly. In fact, thinking of driving, there's a wonderful essay by the late American humorist P.J. O'Rourke called "Ferrari Refutes the Decline of the West" [09] and he describes driving a Ferrari coast to coast across the United States. When they get to the Rockies, he describes how wonderful it is. Upon the flat interstates crossing Georgia, they're limited to 55 miles an hour. And there isn't a gear in the gearbox in which they're comfortable at 55. But again, up into the mountain curvy roads, he says, this is what the car was built for. The steering was frighteningly direct; left brain to the asphalt.

00:59:49 [BT]

Well, and actually the driving metaphor, the context, is interesting because in the case of rally drivers, the co-pilot is not giving icons. The co-pilot is actually reading out off a list, gearings and angles and elevations the whole time. And I'm thinking, the reason they have to be so specific (and it's all spelt out and this is similar to programming a computer), is because you have to be exact in what you're telling. If you took the icons on the side of a road as a curve, what you'd be saying is: "that icon should be exactly what the next curve is". And if it isn't, [Conor agrees] you're going to drive off the road. And that's kind of what some of these languages are like. We look at an icon and we think: "oh, well, that's a general [sentence left incomplete] ..." No, it's not general. It's very specific in the case of APL [chuckles]. It's going to do this. Now, what you need to adjust is figuring out how what it's going to do fits what you want to do. But it's like a rally co-pilot who's saying: "left, right, left, right" (and you have other things to tell you how much left [or] how much right). But all it's going to say is "left, right, left, right". We have to bring other things to make the difference.

01:01:01 [CH]

I think this is what's been in the back of my head, is what you just said there, Bob: sure, at times a sign on the road is exactly what you need. You need to very quickly ingest a certain piece of information but the details and the specifics (whether it's the degree of the turn) is not essential; there's a turn, you need to slow down. But I think the point that Marshall was making earlier is whether something is to be a primitive or to be in a library or a system function. Sometimes [with] something like split, there are so many different variations of split-drop, split-keep-left, split-keep-right, split-whatever. Like literally, if you go to Haskell, they have a data.list.split. And there's [chuckles] a double-digit number of split functions in there. And then there's a bunch of things that are slightly different than splitting; you end up with a list of lists, but it's not really splitting per se. It's like a form of splitting but they call them different things. I think that's where the interesting discussion [is]. I think we can all agree that there are certain things that definitely belong in the primitive symbol category. The question is: where do you draw the line? And is something like partition really ... should it be a primitive? And if it's not going to be a primitive, what do we expect the user to do? Do we expect them to learn the idioms, like Aaron Hsu says? Like, we don't need libraries; just learn the idioms. The more and more you program in these languages, the more and more you'll recognize the idioms. The same way that we see average and we just instantly recognize it; like, that will happen. Or do we start to put these things in system functions or in libraries? And I think that's where, when you start to enter that discussion, I play around with Jello. Jello is just like: "we get rid of all the primitives and just everything can be a keyword". It's like, I actually don't mind everything being a keyword because then I can autocomplete on everything, right? When I start typing, we can autocomplete to Jello, and now I just get, like, a dropdown of all the things. And I was like: "oh, there's 17 different split functions here". I can just choose the one I want. Anyways, I think there's a certain camp of primitives that we're all in agreement that yes, these things are essential. They are fundamental. We want them to be in the core language as tight small things to type. But then there's a different set of things where I'm like: I don't really know what is the best experience for people that want to use these languages. Adám?

01:03:19 [AB]

I once was with one of my coworkers picking up a car at the rental place; I think it was next to Heathrow Airport. I thought it was hilarious that [there was a] sign that spelled out in English saying: "Humped Zebra Crossing." [Chuckles] I would not want to read that at high speed.

01:03:39 [ML]

That's actually an official name. I always thought that was just kind of a nickname or something. For those unaware, this is the crosswalk where it's drawn with big stripes on the road. So in England (maybe in other places) it's called a zebra crossing because of the striped appearance.

01:03:54 [AB]

And then it's elevated a little bit over the road surface to force you to slow down, so it's humped. It's a humped zebra crossing. But that just parses wrong in my head, and I would just get distracted [Marshall agrees].

01:04:07 [ST]

I'd love to see a humped zebra. I'm sure it would look very satisfied [Conor laughs]. But in terms of a danger warning [sentence left incomplete] ... You see, I misparsed the expression. I love your point here, Adám. Three word warning; that starts to engage my language parser and my mind goes off somewhere which isn't driving. So if I'm riding shotgun in a car and I see danger, I don't describe it. I just go, "Hump!"

01:04:39 [AB]

Maybe it's even something more built into our whole neural system. If somebody says, "Stop!" or somebody holds up their hand stretched out in front of you, the hand gets you a much stronger reaction. You almost cannot not stop there. There's something about the symbol that's directly associated. It bypasses the lingual part.

01:05:02 [ML]

And even with words, we can communicate using the tone. Like if you say, "I don't think you want to do that," there's a rising tone there; regardless of what I said, you would notice that something – you need to pay attention.

01:05:15 [AB]

It's very different than, "I don't think you want to do that.". But going back to the words versus pictograms, I tend to not use in my head the official name for APL primitives when I read them. What they mean is very clear. But what they mean in the context does not have a single English description for every context. (I'm saying this a bit weird; maybe somebody can put it better). The same symbol does the same exact thing in every context because that's how they're defined. However, there is no English word that is appropriate in the same context if I was to spell it out in English. And then you could try to find some word that is ambiguous; vague enough to fit in but there's very much a danger, I think, of implying a certain usage: "this is what you should use it for". And that limits your ability to construct things out of these LEGO pieces because you have been led into a specific context. By associating functionality with a symbol that's kind of abstract, it can hint at what it does, but it's still abstract. And then there's a bigger chance of allowing this galaxy brain thing to think about all the possibilities: "how could I use this?" Maybe a small example (probably not the best example of it): common in J, BQN [and] APL: we have used the same symbol for rotation and reversal. It depends on whether it has a left argument or not, which one you use. Very often, I only have two elements and then rotation and reversal are the same. How could I possibly give good names for this? I can use a parameter (a boolean on the left of a rotation), to choose whether or not I want to reverse. So if the keyword was ROTATE, then that's misleading because what I'm actually doing is a conditional reverse. And you certainly don't want to call the rotation function "conditional reverse" because then in the general case, with more than two elements, that doesn't fit either. So should you have synonyms? And it's all ugly names anyway.

01:07:49 [ML]

Well, I guess the word-using approach would just be to write a new function with a name that has the same implementation, but now is called something else.

01:07:59 [AB]

That seems very silly for a programming language to have but you have it in COBOL, right? COBOL has like 300 something built-ins because they have synonyms and with a final S and without the final S so that you can spell your code out in some pseudo-English.

01:08:15 [CH]

So wait, I'm a bit confused. Was your example that you're using the ROTATE primitive, which also doubles as the reverse primitive (which is a whole other conversation about ambivalence), but you're using ROTATE, but in the case where you only have a two-element array, it's no longer a rotate; it's a reverse?

01:08:33 [AB]

It's a conditional reverse based on the boolean on its left. If I do a 0-rotate, then it's "do not reverse." If I do a 1-rotate, it is a "do reverse." Conceptually, what I'm thinking about is: "should I take this pair and flip them around?" I want to reverse it or I don't want to reverse it. I'm not rotating anything. It's not about taking the first element and sticking it at the end and shifting everything over. I'm either reversing or I'm not reversing. It's conditional reverse and the condition is the left argument.

01:09:01 [ML]

I do think I would still pronounce that ROTATE if I were reading out the code in my head.

01:09:07 [CH]

So that's the thing. The argument here is that you have an alternative name that better describes the semantics of what you're trying to do or convey but it still also is just either a 0-rotate or a 1-rotate. That's not, not what you're doing, right?

01:09:25 [AB]

Yes, and because of people thinking of it like that, they end up writing code (and I've seen this in the real world) like "reverse power operator condition."

01:09:38 [CH]

Oh, I see what you mean.

01:09:46 [AB]

That's because they've associated this too strongly with an English translation. If they just thought about it as a concept, then you don't end up with that kind of awkward statement.

01:09:48 [ML]

Well, but I mean, if you just write the version that says what you want to do, then you don't have to worry about the names not meaning what you want them to.

01:09:56 [BT]

No, I think what Adám is saying is if you get too tied up in what you think is happening [Conor agrees] and then you add another argument (like instead of a list of two, it's a list of three) you think it's going to reverse. It's not going to reverse anymore [Conor agrees again]. Now it's going to rotate because that's what it does. But what you've done is you've said, "Well, look, reverse and rotate are the same for a list of two." It doesn't extend to a list of three, so that's an incorrect way of thinking about it.

01:10:24 [CH]

I understand Adám's point now, and you did actually prefix that whole thing saying this might not be the best example, but I can think of ten better examples because C++ is awful at this, and I point it out all the time. The best example in C++ [sentence left incomplete] ... I mean, there's so many good examples. Is this one the best?

01:10:40 [AB]

You mentioned adjacent differences, right?

01:10:42 [CH]

adjacent_difference(), yeah, is that it hardcodes the semantics of the default binary operation into the name, which completely obfuscates the fact that that binary operation doesn't need to be MINUS. It can be anything. Another example that they just added in C++20 is they have a view (if you're familiar with C++) where basically you can chain these operations together, and if you have a list or an array of tuples and you want to extract out either the first, second, third, fourth of [however] many elements you have in your list of tuples [sentence left incomplete] ... If you want the third one out, you can call a view called elements and then you pass in as an argument 2, which is the second index (so 0, 1, 2; it's 0 indexed). But we have aliases for index 0 and index 1 (an alias just being like an alternative name that is maybe shorter and easier in terms of understanding). But the alias names are keys and values, which clearly if you're familiar with associative containers has to do with either tree maps or hash maps. And so if you're parsing through or whatever, you're using views to loop through these containers, that makes a ton of sense. But potentially you don't have an associative container and you just want the second element, but now do you want to use VALUES in order to access the second element? . Well, that's just like Adám's saying, it's like in these cases, you're just choosing bad names. It's then going to completely obfuscate the generality of what this thing could be used for and it's just like a nicer way of spelling elements 1. But I don't want to spell VALUES if it has nothing to do with key value pairs.

01:12:27 [ML]

Well, and you better hope you don't have another column in between the keys and the values. Like if you have an isDeleted entry, now it's called VALUES.

01:12:35 [CH]

Yeah, yeah, I guess. I mean, most of the times you're not going to have that. But yes, if you have done something where you took your key value pair and then kicked the values to whatever the third element in your tuple because you inserted something. That'd be rare but in general, I completely agree with the point that Adám is making. It's the semantics that are important and if you name something, not even poorly, but just if you name it well, you can still obfuscate some of the uses for these things, like a nicer way to implement a conditional reverse is by using ROTATE with a boolean left argument. But you're not going to see that unless you think of what is the full capabilities of this dyadic function versus like: "oh, I need a REVERSE. I'm going to reach for REVERSE."

01:13:27 [AB]

Here's another couple of other examples from APL. We've got max and min but those names very much give you the context of: "I'm going to compare things and choose one." But then some programming language might also add a clamp function; I want to clamp my values between these limits. That's just max and min but you might not have thought about that. Every once in a while, I have somebody ask me: "You've got AND and you've got OR, you've even got NAND and NOR. Why don't you have an XOR?" Well, we do; the problem is you call it NOT EQUAL. I just call it the symbol. That's the symbol for XOR. It's also the symbol for NOT EQUAL but you can't find a good name that is both. Did you know that APL has a formal logic IMPLY function?

01:14:16 [CH]

A what?

01:14:16 [AB]

IMPLY. It's normally written in traditional formal logic with a right arrow.

01:14:22 [ML]

Yeah. And it goes backwards.

01:14:31 [AB]

Yeah, I know. This is slightly bothersome, but that's how it is. That logic gate (the imply gate), exists in APL. It's generally known as LESS THAN OR EQUAL TO but that's a problem. Don't call it LESS THAN OR EQUAL TO. Just call it that symbol that it is because it's both.

01:14:41 [ST]

We need a series of grunts at different pitches.

01:14:46 [CH]

Yeah [laughs]. This makes me think of Bjorn Fahller [10] who's a speaker in the C++ world. [He] gave a talk back in November, a couple months ago, where he referenced my composition intuition talk and had a rant on combinators. I made a comment and then he responded saying he actually is a big fan of combinators and function composition but his issue is that the name of these things are like, the B combinator and the B1 combinator and then it's: "Oh, it's so fun because we gave them bird nicknames". And he's like: "I'm not calling this thing a B or a blue bird. It's just silly. I'm calling it compose". This is the whole thing, that we're saying: "Don't name these things". But we have to. We need a way to refer to these things and is the array way (the APL way), of calling them ATOP and OVER and BESIDE or is the BQN way of calling them BEFORE and AFTER (and they borrowed some of them) or is the original abstract B, B1, k.I, S? None of them are good in my opinion because these things are so abstract, it's just like unary before binary, binary before unary; now we've got to turn it [sentence left incomplete] ...

01:15:56 [AB]

But surely you can agree that those bird names and letters are inferior to what BQN and APL calls them. The letter is the worst because that's nothing we as humans can even associate with. There's no mnemonic value. It's just random names. The birds at least is kind of cute and it's easier for humans to visualize something and remember it. All these mnemonic techniques where you associate things with pictures and things. That helps a little bit, but it still doesn't really say what it's about. There's nothing about this bird that makes it apply functions in this order not that order. At least BQN and APL use temporal or spatial words to try to give you some kind of idea about what's happening.

01:16:47 [ML]

Well, and another thing we've done is picked a smaller subset of the combinators. We don't have any that are just like apply this thing to that thing and then to that thing over there. We don't have these big compound combinations. We break them into more individual combinators. We have a lot less things to name and give symbols to.

01:17:10 [CH]

You said surely you would admit that the bird names and the letters are worse. I'm not so sure. I agree in essence with your statement but your statement presumes that the names that were given were helpful and at minimum neutral and not harmful. I can't say that. Definitely for some of the ones like BEFORE and AFTER, monadic and dyadic BEFORE and AFTER in BQN, nailed it. Beside? Which beside? To the left or to the right? I can never remember BESIDE. It is BESIDE, but I don't know which BESIDE. OVER and ATOP?

01:17:50 [ML]

The way BESIDE works usually is that if you take the function in parentheses with BESIDE and you remove the parentheses and you remove the BESIDE combinator, it does the same thing.

01:18:04 [AB]

You don't need parentheses at all. It's just that f BESIDE g (f∘g) is the same thing as the explicit expression. Again, a little bit of the tacit thing. If you have the tacit derived function, (f BESIDE g) is equivalent to having the explicit phrase f BESIDE g, where BESIDE here just means ... [sentence left incomplete].

01:18:24 [CH]

Oh, is that what it means? Well, see, that's the thing. We needed a verbal explanation of what BESIDE meant in order for me to know what BESIDE meant. I thought BESIDE was just a poorer version of the BEFORE and AFTER because I think BESIDE does correspond to B and D or B1 and D?

01:18:41 [AB]

I can never remember these letters [chuckles].

01:18:43 [CH]

Well, I guess the thing is good names are always better than something abstract but the problem with these things is they're so abstract that it's very difficult to find good names for them.

01:18:54 [AB]

Yeah, ATOP and OVER are not ideal either. Iverson called it ON. It's the same kind of thing [Conor agrees] as something being placed higher than something else, but there's nothing really to disambiguate them in their names. And, yes, it is very hard to name these kind of abstract things but at least there's an attempt at naming them. But that's only when we need to speak about it. It happens to be that this is an audio-only podcast.

01:19:18 [ML]

Yeah, yeah. More importantly, we have the symbols.

01:19:19 [AB]

Yeah, the symbols are better [Conor agrees]. And even they have to be relatively abstract. The BQN ones are pretty good.

01:19:26 [CH]

Here's the solution to the problem: we need to evolve to communicate via symbols [chuckles] and just get rid of language.

01:19:34 [AB]

Well, I mean, you can (and people also do sometimes) spell out the code in terms of the symbols rather than in terms of the functionality. Like whoever says index generator 10? You always say iota 10. Other languages have even picked up on the name iota, which is just the name [chuckles] that we call it. One of those APL primitives that doesn't really have any mnemonic glyph: it's just a Greek letter.

01:19:59 [CH]

Oh, oh, careful, Adám! Careful. This is like our one thing that we've gotten into the mainstream languages and now you're telling us there's no reason for it?

01:20:03 [AB]

I know. I know. And that bothers me. No, I mean, you could say that iota is like an i, and it's like index generator or indices or integers or something like that, but it's kind of weak.

01:20:17 [ML]

Well, now, hold on. IOTA is the one thing we've gotten into the mainstream languages that's obviously traceable back to APL because of this completely arbitrary choice. The name REDUCE also comes from APL, but it is not so obvious that it comes from APL because, you know, anybody could have come up with that name, right?

01:20:37 [AB]

Yeah, iota is completely arbitrary, so it has to be from APL. [Everyone laughs]. Right, but there's only so much we could do. I mean, one thing I thought about: if you weren't constrain by Unicode (and it's very hard to get additional characters into Unicode, especially if they haven't been used before; [chuckles] that might involve violence or threats of violence if you need to do that) is that we draw sometimes these tree diagrams of what the various combinators do and those can be stylized, simplified basically to something like a Y or an upside-down Y or like a little house symbol without the floor or something like that. And those symbols might actually be nice for the combinators. Might. I'm not sure. I never used it in practice for practical reasons.

01:21:24 [CH]

Ooh, that's an interesting idea. I never thought about that.

01:21:27 [AB]

So maybe there's a way to visualize things. Some things are harder to visualize than others (kind of abstract) but I think it helps that we are array-oriented so it's always in terms of a concrete thing, and you can take an example, you can take a matrix and say: "okay, this is what it does to the matrix." We can come up with something, possibly.

01:21:47 [CH]

Or the listener could. I've just realized; we've blown past the hour-and-a-half mark. At some point I saw 52 minutes, and I don't know what happened to the last 40. But we will wind this down by saying we apologize to the excited listener for ... [sentence left incomplete]. I mean, I guess in the title you did not see tacit number 6, so it wasn't until I said that you saw in the title ... [sentence left incomplete].

01:22:06 [AB]

Surprise!

01:22:07 [ML]

It was left unsaid.

01:22:09 [BT]

Believe me, they are not going to see tacit number 6 in the title. That's going to be internal [laughs].

01:22:16 [CH]

Yeah. Well, I mean, they're going to hear, hopefully, at one point, being like: "all right, we're going to talk about tacit number 6," and they're going to be like: "why didn't the title mention it?" And then they will realize at the 30-minute mark that no tacit or minimal tacit will be talked about. We do promise tacit number 6 in the future, and we'll talk about Jelly and KAP (I guess at this point, probably after we talk to Elias, who is the creator of KAP). I think what we should do [is] go around as (what do you call it? I can't actually remember the name of that) ... [sentence left incomplete]. We'll give everyone sort of a last one sentence, final thoughts on primitives versus keywords. You can say whatever you'd like. Bob has his hand up.

01:22:56 [BT]

I will say right off the bat: if you're building something in LEGO, choose your pieces carefully.

01:23:00 [CH]

That's your final comment? [laughs]

01:23:02 [BT]

That's it.

01:23:03 [CH]

All right. We'll go to Stephen and then Adám, and then we'll finish with Marshall.

01:23:04 [ST]

Symbols.

01:23:05 [CH]

Perfect. Adám?

01:23:08 [AB]

Mostly symbols.

01:23:09 [CH]

Marshall?

01:23:11 [ML]

Why don't you just experiment and try both? [Conor laughs]

01:23:15 [AB]

There was a version of APL+ [11] (if I remember, right) that allowed you to write like hash and then a name (they didn't use hash for something special like Dyalog does). And then you could spell out primitive names like that and use it inline. You could toggle this functionality on and off. I think it just disappeared. For those people who are courageous enough (looking at you guys on Hacker News), to actually try array languages, I think you'll quickly find that using the symbols is actually very nice [chuckles].

01:23:50 [CH]

I agree.

01:23:51 [ML]

Hacker News is an example of people who have no courage, I assume [Conor laughs]

01:23:57 [CH]

Yeah, we'll leave a link to the most recent Hacker News APL thread that I think happened in the last week or two. There were some great comments, but then I think the top comment is a pretty decent review, but then there were some other ones; I was reading them and I was like: "oh, boy; there's the orange website." There's always a mix.

01:24:15 [ML]

Well, whenever anybody makes all these crazy assumptions about what APLers think, I always leave a link to the forum and say: "we're right here; come talk to us if you want to find out whether you are correct about this thing you're assuming." Nobody's ever joined and asked any questions.

01:24:32 [AB]

I wonder how many go to any of our online playgrounds and actually spend one minute trying it out [chuckles]. I would say try out symbols.

01:24:44 [CH]

Try out the symbols, folks. All right, we'll send it over to Bob.

01:24:46 [ML]

But try out the keywords if you haven't tried out the keywords [Conor laughs].

01:24:51 [CH]

I think there is a version of ... is there a version of J or a module in J that wordifies all of the ... [sentence left incomplete]

01:24:58 [BT]

Primitives. Yeah, yeah. I think it's called PRIMITIVES. Yeah and they've wordified it. The point is though, you can do that but I think Henry's pointed out that there's no way he's going to do any optimization on that because, I mean, how do you know what people are going to use as words? But the actual symbols (the combinations, the digraphs) he can optimize on and that's why if you start to substitute your own cover functions for that, they'll never get optimized because he's not going to recognize those.

01:25:28 [CH]

But, I mean, there you go. Go to J, import the primitives module and that can be your stepping stone to ... [sentence left incomplete]. And you very quickly will realize that having to type out REDUCE instead of the slash (/), you're going to get very tired of that very quickly and then you're going to start typing the slash, then you're going to start typing the other, and then before you know it, you're going to be full digraphs and trigraphs, etc.

01:25:48 [AB]

You can do this in Uiua, right? [In] Uiua, you could. I mean, I asked this question, whether you can prevent the Uiua system from changing your keywords into the symbols [chuckles]. Potentially, you could copy it.

01:25:58 [CH]

Oh yeah, because you...

01:26:01 [ML]

You could go the other way [chuckles].

01:26:03 [AB]

Yeah. Stick it somewhere before you execute it so you can restore your code because it gets mangled every time you run it. And you can program WeWare entirely in keywords. So, try it out.

01:26:15 [CH]

Yeah. I mean, for a language that doesn't have ambivalence, it's a very simple script to just create a dictionary and convert stuff, whereas in APL, J [and] BQN, it's going to be a lot more tricky because in certain cases (like the ROTATE/REVERSE) you're going to have to choose – you're going to either have to encode them all into reverses or whatever or figure out the context to replace them. But, yeah, I'm pretty sure the ... [sentence left incomplete].

01:26:39 [AB]

That cannot necessarily be done, not in APL, for example. You can't pre-parse everything [Conor agrees]. But there's no particular reason why REVERSE and ROTATE as keywords couldn't be both REVERSE and ROTATE. They're just silly labels slapped on top, and they actually just cover for the symbol, not for the functionality.

01:26:58 [CH]

Anyways, to the listener, some of you already are programming in array languages, so you don't need to go try anything out. But if you happen to have stumbled across this episode for some reason and you haven't tried out the array languages, go take them for a spin. Let us know whether you like symbols [or] keywords better. I mean, q is the easiest way to try out keywords, to be honest, instead of going to J and loading the primitives module. Just go check out q. They've got keywords for free, and let us know how it goes. Bob, people can reach us at ...

01:27:24 [BT]

(Oh, look at the time! [Conor and Stephen laugh]) contact@arraycast.com is where you can reach us and we look forward to your comments. We've had a number of really good comments over the last couple of weeks and always enjoy them. I get a chance to look at them first and then I fire them off to our Slack channel where everybody else sees them too. Sometimes there's comments that come back and I'll forward them back to you. But know that they're always being read, because we do appreciate them. And when you make kind comments, thank you for the kind comments as well.

01:27:55 [CH]

As I said before, we apologize for the lack of tacit today but it might be a couple months, because like we said, we've got a bunch of guests lined up. But it will happen at some point in the future. With that, we will say, happy array programming!

01:28:08 [everyone]

Happy Array Programming!

01:28:10 [CH]

All right, we nailed that landing [laughs]

[MUSIC]