I think that the vast majority of people who complain that these languages are unreadable and who insinuate that people who use and like them are basically just showing off are fundamentally uninterested in the possibility that there are possible positive trade offs to this style but for those who are genuinely interested in why some people like to program this way: Imagine having to do math with no symbols. that means 1+1 is now one plus one. Now imagine having to do that in the context of graduate levels mathematics. I am quite sure nobody calls a2+b2=c2 unreadable as compared to a squared plus b squared equals c squared and I dont know any one who wants to do algebra that way. Well the same principle is why array programmers like this style. I dont expect you to take my word for it im just letting you know what these other weird crazy people see in array languages that you dont. This allows one to think faster and further than they could encumbered but a heavier syntax. Is this way of programming the best no. Should everyone learn it no. Are there trade offs yes. Is it worth your time, quite possibly not. But thats true about literally everything in programming.
> Imagine having to do math with no symbols. that means 1+1 is now one plus one. Now imagine having to do that in the context of graduate levels mathematics.
That's a good way to put it. It's pretty hard to convey this to someone who hasn't actively tried and solved real problems in such languages though. You don't realize how much the "words get in the way" (as Granny Weatherwax would say) until you give an array language a good chance.
Another pop-culture quote that resonated in this regard is from The Matrix:
> Your brain does the translating. I don't even see the code. All I see is blonde, brunette, redhead.
All I see is range, sum-over, divide. The symbols turn into the concepts directly in your head - not as conscious translation, but in the way I imagine Chinese or Japanese kanji characters translate directly in the head of a native speaker.
I understand the appeal of array languages — they provide very convenient shortcuts to common loop constructs in traditional imperative scalar languages. Their usefulness is manifest in the popularity of NumPy (and its derivatives, e.g. TensorFlow, PyTorch, JAX, etc.), MATLAB, Julia, R, and other Iverson Ghosts [0]. The rise of map/reduce/filter operations in common scalar programming languages is also testament to array languages' usefulness.
I understand (though do not personally agree with) the appeal of extreme terseness — there are arguments to be made that maximizing information density minimizes context switching, since it reduces the amount of scrolling. Personally, I find that large displays and split buffers mitigate this issue, whereas the mental overhead of using my short-term memory to map dozens of single letter variables to semantic definitions is much higher than having to flip between splits/marks in my text editor. (The fact that the aforementioned Iverson Ghost languages are popular whereas APL and its derivatives are not is evidence that I'm aligned with most people in this regard.)
I don't understand why people rarely make the terseness argument for non-array languages, even though it's just as easy to write tersely in them — the Obfuscated C Competition is a prime example [1]. Is it just due to the influence of APL, or is there something special about array languages that gives them a unique proclivity for terseness?
One thing humans are good at is pattern recognition. Terse APL is - once you are used to it - very recognizable.
Many constructs take less characters to algorithmically specify than to name: (Examples in K because that’s what I know best):
(+/x)%#x computes the average of a vector x; or the average of each column in a 2D matrix x; or other averages for other constructs. It takes about as much characters to spell “average”, which is considers too short a name in modern C or Java - and yet, the code is instantly recognizable to any K programmer, needs no documentation about how it deals with NaNs or an empty vector or whatever (which your named C/Java/K routine would - does it return 0? NaN? Raise an exception? Segfault?)
And ,// (yes - that’s comma slash slash) flattens a recursive list. Way shorter than its name , and it’s the entire implementation.
Are these the most numerically stable / efficient ways to average or flatten? No. But they are the least-cognitive-load, fastest-to-grasp-and-pattern-match when reading code. Once you are used to them.
The appeal of Iverson languages also comes from a good selection of primitives. Most modern languages such as C++, Python, Nim, even Rust have an implicit focus on the “meta” programming: they give you the tools (templates, macros, classes) to build abstractions, with which you later build your actual computation. K / J / APL / BQN expect you to do the computation with much fewer abstractions - but provide primitives that make that incredibly easy.
For example, there is a “grade” primitive which returns a vector that - if used to index your original list - would sort it.
Now, say you have a list of student names, and ages, and you wish to sort them - once alphabetically, once by age. In idiomatic C++/Python etc, you’d have a “student” class with three fields. Then you’d write some comparator functions to pass to your sort routine. (I am aware of accessors and the key arg to pythons sort; assume for a second they aren’t there).
In K/APL/J, you’d just have 3 lists whose indices correspond: and then it is just:
name[<age]
Read “name indexed by grading of ages”. They’re a terser version: name@<age read: “name at grade of age”
The terseness compounds. Once you are used to it, every other programming language seems so uselessly bloated.
None of these things apply to obfuscated or shortened C.
Arthur released K source code, which is C written in the same style. It does not have the same appeal.
These are all great examples of the advantages of array programming syntax versus imperative scalar programming syntax, but do not IMO demonstrate the advantage of terse array programming syntax.
For example, the NumPy equivalents of your examples are not materially longer than their APL/J equivalents, but are easily readable even by people unfamiliar with NumPy:
> the average of a vector x; or the average of each column in a 2D matrix x
x.mean(0)
or, to use your example verbatim,
x.sum(0)/x.shape[0]
> flattens a recursive list
x.ravel()
> name indexed by grading of ages
name[age.argsort()]
Though for this application, you’d probably be using a dataframe library like Pandas, in which case this would be
You didn’t address points I already raised about mean() - how does it handle an empty vector? How does it handle NaNs ? You have to read the documentation to figure that out. In K, the implementation is in front of your eyes; NaN handling follows from “over” / reduce / addition semantics; and empty vector from reduce and division by zero semantics. It is all consistent by construction, and follows from basic properties. The same cannot be said about mean() or sum().
The call to .ravel() is strictly less powerful than ,// which would flatten a matrix, but also a lisp/xml style recursive list structure. And it is the actual implementation, not some weird name! It is “join over until convergence”.
With respect to sorting, in K you would also likely use the built in relational operator “?” (select).
Notice how you need to import pandas and numpy, and then know their docs well to find the routines you want and how they behave in edge cases? And that’s in addition to actually knowing Python?
K has all of that built in. You just need to know the basics (which takes more work than knowing Python well, admittedly). Most from there is derived by construction. It does have some 80 or so non-trivial primitives, but then you need much fewer libraries, often none.
(And, that’s not a for/against thing, but … in case you wonder, the K executable does that in about 200K binary without dependencies; REBOL achieves similar terseness of final programs by completely different means and philosophy, and also packs that into a 400K executable)
The point is that every idiom beagle3 noted is a simple and straightforward combination of general building-blocks, whereas nearly all of your "equivalents" are a one-off special-cased feature or function that needs to be learned on its own. The power and expressiveness of APL-family languages comes from the fact that they have a very small number of well-chosen parts that can be combined in flexible ways. Those patterns of combination become a higher-level vocabulary that fluent programmers grasp at sight, much as experienced readers of English learn to recognize the shapes of entire words at a time. This type of visual pattern recognition is facilitated by brevity.
APL-style idioms are not at all comparable to functions on a class or within a library, because idioms are self-describing in their entirety, requiring only an understanding of the primitive operators of the language, whereas a named function obscures and subordinates detail.
I think it's because obfuscated C is not nearly as succinct as the modern array languages. The formula for average in APL is just a few characters. I'm guessing the C equivalent would be a lot more and when you try the same for a real application, you'll have a very big overall difference.
Mathematical notation actually pays quite a bit of attention to readability, to visual separation of things to make the whole easier to parse. Multi-story fractions, subscripts and superscripts, oversized or miniature symbols, parens, etc, etc. This is why math in a textbook very often looks much more readable than the same math in typical Python or Fortran code.
I wish APL derivatives embraced some of these ideas, and made their magic spells easier to parse visually, and to format for readability. I don't know how to achieve that easily. Mathematical notation took centuries to develop. It took quarter of a century for programming languages to normalize indentation. Maybe APLesque languages will eventually come up with a notation that's less impenetrable than APL / K / Q, but less verbose than Pandas.
Well some of what you mentioned has been implemented in array languages and some like superscript and sub script was part of the original apl book (the book on the notation pre the implentation). Its somewhat ironic, orignally apl was supposed to make math notation more readable (it was originally just a math notation) but many people dont see it that way. if you are interested in super scripts and the like you might check out bqn and uiua which both are doing interesting things with the symbols. although uiua in particular suffers from having to choose from a set of symbols that comes from unicode and therefore sometimes look a little off to me
Iverson's Notation as a Tool for Thought is an argument in favor of the above. I don't think it's flatly wrong, but I am skeptical of the more strong forms of it.
I think it's important to remember that APL was born of an era where having a keyboard dedicated to a single programming language was reasonable.
I think there's a lot of middle ground between the more line noise syntax of say jsoftware, or a pure lisp style prefix notation.
This is a little snippet from Stevan Apter, a k programmer that has an old school home page with a lot of array language curiosities:
If you look at the pseudo code example at the end using words vs ascii glyphs, I think that's quite readable while also concise. It uses k's bracket notation to easily specify slices of nested arrays.
Interestingly kxsoftware themselves went this route with q (Stevan's essay predates this I believe). There they kept nearly all the power of k but exposed it va a more approachable sql like syntax.
I thought it was another one of those cryptic, inscrutable languages, but following along the explanation of the prime function reveals it’s not actually as complex as it looks, and is a quite straightforward right to left application of operators. Not nearly as bad as I first thought.
> Imagine having to do math with no symbols. that means 1+1 is now one plus one
I think that's exactly on point. Here are two examples from Euclid which demonstrate why mathematics, and likely science, were stunted for millenia:
"if a first magnitude and a third are equal multiples of a second and a fourth, and a fifth and a sixth are equal multiples of the second and fourth, then the first magnitude and fifth, being added together, and the third and sixth, being added together, will also be equal multiples of the second and the fourth, respectively."
a(x + y) = ax + by
"If a quantity increased by three becomes five, then that quantity has to be two".
I would probably prefer this, because then I could actually look up the unfamiliar terms and have some hope of eventually figuring out what the equation meant, instead of being brought up short and stumped by inscrutable notation.
even for actual calculations? if so then touche. But (and I may be wrong) I feel like this comment is coming from a place of I need to look up some formula which for some other task. Like say im making a video game and I want some geometry formula. In such a case what you care about is not how easy a notation is to use but simply getting info as fast as possible in which case learning new symbols just gets in the way rather than actually writing correcting algebraically manipulating and extending (keep in mind im using math as an analogy for programming in not actually speaking about array languages being used _for_ math necessarily). This is a fair criticism of array langauges you do need to learn something which is quite different from the usual english based languages and they are not great for black boxing i.e you have to know the domain of your problem because relying on libraries is impossible at worst and not any better than python or java at best. That being said I find them more scrutable than most langauges partly because of the tersity. And partly because of the limited vocabulary. You can look up unfamiliar operators very easily in array languages because they all come with multiple (some more for reference some more for learning) easy to go to places to do so. But more importantly there really are only so many so you can learn them all (in the same way you already learned your numbers + - 3 %, and so on) once you do you dont feel the need to look up 6 or & or + mean you just know them. In contrast in a language like python or javascript im constantly looking up how things work because there are just infinitely more things the source code of which is often hard to get to and when you find it it is very long (and therefore (for me) hard to read). When I see an array function I actually can scrutinize them when I see a python function I need to hope that its simple and named in a way that makes automatic sense to me or give up and look it up somewhere else (in docs say).
That's fair. My remark was a bit of a tangent, borne of frustration over years of trying to read papers relevant to my interests where the juicy bits are all written in math notation and therefore inaccessible. I have to go track down some open-source implementation of the idea and read that to understand what the paper is trying to say - any programming language at all, even one I've never seen before, will be easier to understand than the original symboldegook.
I can imagine that it's a much different situation with array languages, where the notation is actually learnable, because it is defined and documented.
I just fail to see the point. I could see the use for some convenient functions for array manipulation, but why not just implement these as a library in any existing language?
>This allows one to think faster and further than they could encumbered but a heavier syntax.
How does the programming language limit your ability or speed of thinking, lest when the fundamental data types and operations are the same? The hard work is always knowing what to implement. Saving some keystrokes for reversing an array or whatever other array manipulation is hardly a game changer.
It's not about saving keystrokes, it's saving brainpower and effort when reading, writing, and modifying code. Instead of thinking about control flow and nested loops when doing multiple complex operations on an array, you're thinking only about the array operations. Abstracting away the loops and control flow frees the programmer from the most tedious and error-prone parts of programming.
It seems more of a proof-of-concept than a real implementation though - at least, the APL wiki calls it a "toy dialect of APL" and says that it "works on a minor subset of APL". [3]
This looks more like an interpreter.
What I mean is just take the symbols in Klong and write them as methods on arrays. Sure the syntax won't be the same, but does that really warrant a whole new language?
Why not a whole language when so many problems can be easily reduced to these few methods?
It's worth noting that almost all array languages are interpreted, and iteratively constructing a program in the interpreter is common. This style would be painful in a more verbose and lower-level language but works great for ultra-high-level array languages.
I think there is literally nothing I could say that would change your mind. You've already decided what you think. There are a number of benefits but none that I could write out and have you someone who is uninterested immediately take my word for it and go home a fan. But I'll try to answer your (probably rhetorical) direct question. "How does the programming language limit your ability or speed of thinking". Again tell me how it is you do difficult math? Do you write out english or do you work with notation that makes it easier to feel and calculate your way through a problem. if you wanted to write a program in a new domain do you honestly think you would come to the same level of understanding of the topic at the same speed if you use assembly vs python. Yes the hard work is knowing what to implement; arrays languages help its users know what to implement. Ultimately, these are all just claims I can't prove to you what experiences you will or wont have if you learn the languages. You wont just believe and you shouldn't just believe me. If you are interested, learn more and try it out! (theres the apl and k wikis, a discord called the aplfarm a podcast called the arraycast etc.) If not just write array languages off and move on.
Most programmers don't do any math at all, so maybe this is just a niche thats not relevant to most of us, but to answer your question:
If I am thinking about any problem, its outside the scope of any programming language in the first place. My point is, modern functions already make array manipulations simple enough. Even if you're doing something like coding LLMs from scratch, numpy, list concatenations, list comprehension, lambdas, stream/map/reduce all exist and its not nearly an issue to implement them, as is the case for writing assembly vs python.
The prime example in python for example looks like this:
all(x % i != 0 for i in range(2, x))
This pretty much does the same operations in the same order on the same fundamental data structure, so I just don't see what's fundmenetally different about the Klong way of thinking.
Anyway, I don't mean to argue, if it works for you great, I wish I had something new
My point with math is not that this only applies to fundamentally math like things but that these languages do for programming what the math notation does for math problems for me. "if i am thinking about any problem, its outside the scope of any programming language in the first place" yes I felt this way too before I learned an array language. Sorry that was a rude way to put that but I do genuinely mean that. Array languages help me solve problems I wouldn't know how to solve otherwise. that python code looks suspiciously full of symbols and one character variable names :). Maybe it would be easier like this: all(exes modulo index not equal zero for index in range(two, ex)).
one of the biggest differences between the k way and the python way too is actually limitation. in practice python has a bunch of stuff that doesnt fit too well together necessarily but that you can put together to make whatever you want often without much knowledge underlying what youre using (like how one can make a neural network with no linear algebra knoweldge) in the array languages you have a set vocablary and only a few ways of putting them together such that you become fluent with the whole languages and you brain starts to just put whole correct functions or programs together in the way one might do with a natural language you know well. Its a great exprience and it changes how you think. HOWEVER, I wont pretend for a second this does not come at a cost. The real power comes from fluent use of a small vocabulary meaning you dont get the immediacy of libraries, IO has to be dealt with by the programmer more so than in languages where you have alot of help form libarires and frankly non algorithmic code in these languages can be really funky and rarely as good. Unless you are writing very algorithmically intense stuff imo array langagues are best suited to embedded use in another language or not at all. For you and for most people I think things like the python you've shown there works plenty well enough.
Klong was among the languages I looked at when I was trying to pick a language for a project (ongoing but back-burnered at the moment). Ultimately I went for Dyalog APL, but looking at the documentation - and the great website - for Klong I found it quite... charming? If you're familiar with the array paradigm it's pretty straightforward.
Unrelated editorializing - Klong has come up in passing on the Array Cast [0] before, but I'm surprised they haven't interviewed Holm. They seem to be doing less of the "forbears tell awesome stories" episodes lately. Which is a shame because that's probably the single best sub-set of Array Cast episode types...
You just go right to left. 1/2 applied to x^ so x^(0.5), _ is floor so floor of x^0.5. ! creates an array of numbers up until floor of x^0.5. 2+ just adds 2 to every number, and then I lost interest in learning the rest lol.
Yeah I like the python equivalent
def is_prime(x):
return x > 1 and all(x % i != 0 for i in range(2, x))
There's a niche out there where this kind of technology is appreciated. I can even appreciate the technical challenges in making an array language interpreter run fast!
However, unfortunately, the notation is so terse that I can't imagine spending the time to learn this. This looks write-only.
Is there an obvious reason to prefer a k-like language like Klong, over e.g. Futhark[0] or Accelerate[1]?
I can't read anything that is too far out of my fovea. If I look at a word in the middle of a sentence, I can read it, and the two immediately adjacent words. After that, the ability rapidly declines. If the next words after those two are simple like "and" and "the", I can still read them while staring at the middle word. Beyond that, I am aware that there are letters and words, but no decoding takes place. If something fits on the screen, it's nice that I don't have to scroll around, but I certainly cannot see it all at once in a semantic way, only as a picture.
It's more a matter of comfort for me than anything to fit a program in a single screen or a function with a single line - large programs and functions are significantly more anxiety-inducing for me to read and work on. I have to keep scrolling and scanning back-and-forth and easily lose my train of thought and get the feeling that I've forgotten something important.
Folding editors can help. Maybe also if there were a thumbnail of the file in a sidebar, with a rectangle representing the current viewport, that could help reduce the anxiety, by giving you an estimate of how much more is there off-screen.
Beyond that, it's part of the course. Nowadays you will not get to work on a production anything that all fits on your screen. Individual files might, but they are part of a whole that doesn't.
Self-contained programs that fit on the screen are able to do that because they reference a language, and that language is not on your screen. You learned the language and so you don't have to take your eyes off the program to look up the documentation or source code.
I wonder if these extremely terse languages might see a rise in popularity with LLMs, since they save a lot of tokens. The hard part would be training on them, since training data is not as comprehensive as JavaScript, for example.
No idea why emorning3's comment is marked [dead]. It's a good question and in fact Klong arrays are very much like S-expressions. In fact their implementation is pretty much the same, down to using CAR and CDR to manipulate them.
Klong could easily be implemented as a bunch of LISP functions and macros.
I wonder how much overlap there is between users of array languages and of scientific programming languages/dialects like MATLAB, Numpy, and Julia, which are also optimized to operate over arrays. In other words, do K/Klong/whatever proponents realize that there is already a huge community of people who appreciate and utilize powerful operations on arrays to do real work, but just prefer to write something like "max(diff(x))" instead of "|/--:'x"? It's almost the same number of characters and it doesn't require learning a new writing system.
"already": APL dates back to about 1966, and even K from 1993 predates Numpy and Julia. But yes, we do not live in caves and are familiar with these languages. Klong has even been implemented in Numpy, see https://github.com/briangu/klongpy.
I understand that these languages are older; I meant that in the sense that they are nonetheless still trying to recruit new users, but these potential users may already be using something that does something similar.
Oddly enough, the biggest mistake in how I presented BQN early on was thinking only APL insiders would be interested, when in fact the APLers went back to APL and people who hadn't tried other array languages or hadn't gotten far with them were were most successful with BQN. Plenty of people coming to BQN have worked with Numpy or whatever, but I don't think this has the same deterrent effect; they see BQN as different enough to be worth learning. Julia in particular is very different: I don't find that it culturally emphasizes array programming at all.
Array languages like K/Klong are fundamentally different from NumPy/MATLAB in that they're built around rank polymorphism, point-free composition, and tacit programming - not just terse syntax but a different computational model with different performance characteristics and compositional properties.
The world is big enough for people to safely experiment with programming languages. I don’t think there’s any risk to Matlab/Python/Julia (and indeed, many people did and still argue that Julia is excess baggage).
I mean, sure, why not, and I'm not opposed to using array languages as a fun hobby (which seems to be the spirit of this). I just noticed that the selling points in the introduction to the manual were not very compelling to me as a Matlab/Numpy user, and since sometimes people bemoan that array languages aren't more widely used, I just wanted to say, hey we do have powerful "array languages" that imo are strictly better on things that matter for most real work, so it's not surprising.
To be clear, you are referring to the preface to "An Introduction to Array Programming in Klong", right? Having just checked it, I find this to be a very strange angle of attack, because that section is almost exclusively about why the syntax in particular is important. Obviously you disagree (I also think the syntax is overblown, and wish more writing focused on APL's semantic advantages over other array-oriented languages). I think this is a simple difference in taste and there's no need to reach so far for another explanation.
A monadic function in APL-family languages is not related to monads from category theory, which are the ones you see in Haskell, nor to Leibniz's monads.
In this context it just means "one parameter function".
It looks like every apparently free variable in a Klong brace expression is actually bound as a function parameter.
This is so in basic algebra in that we can think of, say, x^2 + y^2 as a two parameter function, even without writing out the full f(x, y) = x^2 + y^2 notation with the f(x, y) head.
A two parameter function would be called "dyadic" in the jargon which calls one argument functions "monadic".
I appreciate the features of these languages (J, K, and Klong), but I do not understand the reason why they have such a hard to read syntax. I think it is a pity; I could see myself using it otherwise. Maybe it is by design, but I do not understand it.
> The same baseless accusations of “unreadable”, “write-only” and “impossible to learn” are leveled at all Iversonian languages, k included.
I argue that these accusations are far from baseless. Sure, I can not cite a study, but neither does he. So I assume it's word against word.
> Readability is a property of the reader, not the language.
In my view this is an oversimplification. Having a steep learning curve clearly prevents adoption. The language design actively contributes to the problem. I'm just not sure on why. Could it be that the authors of these languages do not _want_ them to be used by others?
Search for "teaching" at https://aplwiki.com/wiki/APL_conference. I count at least five papers about teaching non-APL topics using APL. The language is not only possible to read, it's designed for it.
The learning curve isn’t steep. I’d argue the opposite. K is a tiny, tiny language. Put your mind to it, and you’ll be reading it just fine in a weekend. It’s just different. It’s optimised for its wheelhouse.
You could say you enjoy toodling on the piano but don’t understand why reading music has to be so hard. It doesn’t _stay_ hard and it opens up new avenues.
I think that the vast majority of people who complain that these languages are unreadable and who insinuate that people who use and like them are basically just showing off are fundamentally uninterested in the possibility that there are possible positive trade offs to this style but for those who are genuinely interested in why some people like to program this way: Imagine having to do math with no symbols. that means 1+1 is now one plus one. Now imagine having to do that in the context of graduate levels mathematics. I am quite sure nobody calls a2+b2=c2 unreadable as compared to a squared plus b squared equals c squared and I dont know any one who wants to do algebra that way. Well the same principle is why array programmers like this style. I dont expect you to take my word for it im just letting you know what these other weird crazy people see in array languages that you dont. This allows one to think faster and further than they could encumbered but a heavier syntax. Is this way of programming the best no. Should everyone learn it no. Are there trade offs yes. Is it worth your time, quite possibly not. But thats true about literally everything in programming.
> Imagine having to do math with no symbols. that means 1+1 is now one plus one. Now imagine having to do that in the context of graduate levels mathematics.
That's a good way to put it. It's pretty hard to convey this to someone who hasn't actively tried and solved real problems in such languages though. You don't realize how much the "words get in the way" (as Granny Weatherwax would say) until you give an array language a good chance.
Another pop-culture quote that resonated in this regard is from The Matrix:
> Your brain does the translating. I don't even see the code. All I see is blonde, brunette, redhead.
All I see is range, sum-over, divide. The symbols turn into the concepts directly in your head - not as conscious translation, but in the way I imagine Chinese or Japanese kanji characters translate directly in the head of a native speaker.
Yes as someone who was exposed to kanji as a child I can say that at least for me the experience is nearly identical
I understand the appeal of array languages — they provide very convenient shortcuts to common loop constructs in traditional imperative scalar languages. Their usefulness is manifest in the popularity of NumPy (and its derivatives, e.g. TensorFlow, PyTorch, JAX, etc.), MATLAB, Julia, R, and other Iverson Ghosts [0]. The rise of map/reduce/filter operations in common scalar programming languages is also testament to array languages' usefulness.
I understand (though do not personally agree with) the appeal of extreme terseness — there are arguments to be made that maximizing information density minimizes context switching, since it reduces the amount of scrolling. Personally, I find that large displays and split buffers mitigate this issue, whereas the mental overhead of using my short-term memory to map dozens of single letter variables to semantic definitions is much higher than having to flip between splits/marks in my text editor. (The fact that the aforementioned Iverson Ghost languages are popular whereas APL and its derivatives are not is evidence that I'm aligned with most people in this regard.)
I don't understand why people rarely make the terseness argument for non-array languages, even though it's just as easy to write tersely in them — the Obfuscated C Competition is a prime example [1]. Is it just due to the influence of APL, or is there something special about array languages that gives them a unique proclivity for terseness?
[0] https://dev.to/bakerjd99/numpy-another-iverson-ghost-9mc
[1] https://www.ioccc.org, https://github.com/ioccc-src/winner/blob/master/2020/ferguso...
One thing humans are good at is pattern recognition. Terse APL is - once you are used to it - very recognizable.
Many constructs take less characters to algorithmically specify than to name: (Examples in K because that’s what I know best):
(+/x)%#x computes the average of a vector x; or the average of each column in a 2D matrix x; or other averages for other constructs. It takes about as much characters to spell “average”, which is considers too short a name in modern C or Java - and yet, the code is instantly recognizable to any K programmer, needs no documentation about how it deals with NaNs or an empty vector or whatever (which your named C/Java/K routine would - does it return 0? NaN? Raise an exception? Segfault?)
And ,// (yes - that’s comma slash slash) flattens a recursive list. Way shorter than its name , and it’s the entire implementation.
Are these the most numerically stable / efficient ways to average or flatten? No. But they are the least-cognitive-load, fastest-to-grasp-and-pattern-match when reading code. Once you are used to them.
The appeal of Iverson languages also comes from a good selection of primitives. Most modern languages such as C++, Python, Nim, even Rust have an implicit focus on the “meta” programming: they give you the tools (templates, macros, classes) to build abstractions, with which you later build your actual computation. K / J / APL / BQN expect you to do the computation with much fewer abstractions - but provide primitives that make that incredibly easy.
For example, there is a “grade” primitive which returns a vector that - if used to index your original list - would sort it.
Now, say you have a list of student names, and ages, and you wish to sort them - once alphabetically, once by age. In idiomatic C++/Python etc, you’d have a “student” class with three fields. Then you’d write some comparator functions to pass to your sort routine. (I am aware of accessors and the key arg to pythons sort; assume for a second they aren’t there).
In K/APL/J, you’d just have 3 lists whose indices correspond: and then it is just:
Read “name indexed by grading of ages”. They’re a terser version: name@<age read: “name at grade of age”The terseness compounds. Once you are used to it, every other programming language seems so uselessly bloated.
None of these things apply to obfuscated or shortened C.
Arthur released K source code, which is C written in the same style. It does not have the same appeal.
These are all great examples of the advantages of array programming syntax versus imperative scalar programming syntax, but do not IMO demonstrate the advantage of terse array programming syntax.
For example, the NumPy equivalents of your examples are not materially longer than their APL/J equivalents, but are easily readable even by people unfamiliar with NumPy:
> the average of a vector x; or the average of each column in a 2D matrix x
or, to use your example verbatim, > flattens a recursive list > name indexed by grading of ages Though for this application, you’d probably be using a dataframe library like Pandas, in which case this would beYou didn’t address points I already raised about mean() - how does it handle an empty vector? How does it handle NaNs ? You have to read the documentation to figure that out. In K, the implementation is in front of your eyes; NaN handling follows from “over” / reduce / addition semantics; and empty vector from reduce and division by zero semantics. It is all consistent by construction, and follows from basic properties. The same cannot be said about mean() or sum().
The call to .ravel() is strictly less powerful than ,// which would flatten a matrix, but also a lisp/xml style recursive list structure. And it is the actual implementation, not some weird name! It is “join over until convergence”.
With respect to sorting, in K you would also likely use the built in relational operator “?” (select).
Notice how you need to import pandas and numpy, and then know their docs well to find the routines you want and how they behave in edge cases? And that’s in addition to actually knowing Python?
K has all of that built in. You just need to know the basics (which takes more work than knowing Python well, admittedly). Most from there is derived by construction. It does have some 80 or so non-trivial primitives, but then you need much fewer libraries, often none.
(And, that’s not a for/against thing, but … in case you wonder, the K executable does that in about 200K binary without dependencies; REBOL achieves similar terseness of final programs by completely different means and philosophy, and also packs that into a 400K executable)
The point is that every idiom beagle3 noted is a simple and straightforward combination of general building-blocks, whereas nearly all of your "equivalents" are a one-off special-cased feature or function that needs to be learned on its own. The power and expressiveness of APL-family languages comes from the fact that they have a very small number of well-chosen parts that can be combined in flexible ways. Those patterns of combination become a higher-level vocabulary that fluent programmers grasp at sight, much as experienced readers of English learn to recognize the shapes of entire words at a time. This type of visual pattern recognition is facilitated by brevity.
APL-style idioms are not at all comparable to functions on a class or within a library, because idioms are self-describing in their entirety, requiring only an understanding of the primitive operators of the language, whereas a named function obscures and subordinates detail.
I think it's because obfuscated C is not nearly as succinct as the modern array languages. The formula for average in APL is just a few characters. I'm guessing the C equivalent would be a lot more and when you try the same for a real application, you'll have a very big overall difference.
Mathematical notation actually pays quite a bit of attention to readability, to visual separation of things to make the whole easier to parse. Multi-story fractions, subscripts and superscripts, oversized or miniature symbols, parens, etc, etc. This is why math in a textbook very often looks much more readable than the same math in typical Python or Fortran code.
I wish APL derivatives embraced some of these ideas, and made their magic spells easier to parse visually, and to format for readability. I don't know how to achieve that easily. Mathematical notation took centuries to develop. It took quarter of a century for programming languages to normalize indentation. Maybe APLesque languages will eventually come up with a notation that's less impenetrable than APL / K / Q, but less verbose than Pandas.
Well some of what you mentioned has been implemented in array languages and some like superscript and sub script was part of the original apl book (the book on the notation pre the implentation). Its somewhat ironic, orignally apl was supposed to make math notation more readable (it was originally just a math notation) but many people dont see it that way. if you are interested in super scripts and the like you might check out bqn and uiua which both are doing interesting things with the symbols. although uiua in particular suffers from having to choose from a set of symbols that comes from unicode and therefore sometimes look a little off to me
Iverson's Notation as a Tool for Thought is an argument in favor of the above. I don't think it's flatly wrong, but I am skeptical of the more strong forms of it.
I think it's important to remember that APL was born of an era where having a keyboard dedicated to a single programming language was reasonable.
I think there's a lot of middle ground between the more line noise syntax of say jsoftware, or a pure lisp style prefix notation.
This is a little snippet from Stevan Apter, a k programmer that has an old school home page with a lot of array language curiosities:
https://nsl.com/papers/kisntlisp.htm
If you look at the pseudo code example at the end using words vs ascii glyphs, I think that's quite readable while also concise. It uses k's bracket notation to easily specify slices of nested arrays.
Interestingly kxsoftware themselves went this route with q (Stevan's essay predates this I believe). There they kept nearly all the power of k but exposed it va a more approachable sql like syntax.
I thought it was another one of those cryptic, inscrutable languages, but following along the explanation of the prime function reveals it’s not actually as complex as it looks, and is a quite straightforward right to left application of operators. Not nearly as bad as I first thought.
> Imagine having to do math with no symbols. that means 1+1 is now one plus one
I think that's exactly on point. Here are two examples from Euclid which demonstrate why mathematics, and likely science, were stunted for millenia:
"if a first magnitude and a third are equal multiples of a second and a fourth, and a fifth and a sixth are equal multiples of the second and fourth, then the first magnitude and fifth, being added together, and the third and sixth, being added together, will also be equal multiples of the second and the fourth, respectively."
a(x + y) = ax + by
"If a quantity increased by three becomes five, then that quantity has to be two".
X + 3 = 5
X = 2
> Imagine having to do math with no symbols.
I would probably prefer this, because then I could actually look up the unfamiliar terms and have some hope of eventually figuring out what the equation meant, instead of being brought up short and stumped by inscrutable notation.
even for actual calculations? if so then touche. But (and I may be wrong) I feel like this comment is coming from a place of I need to look up some formula which for some other task. Like say im making a video game and I want some geometry formula. In such a case what you care about is not how easy a notation is to use but simply getting info as fast as possible in which case learning new symbols just gets in the way rather than actually writing correcting algebraically manipulating and extending (keep in mind im using math as an analogy for programming in not actually speaking about array languages being used _for_ math necessarily). This is a fair criticism of array langauges you do need to learn something which is quite different from the usual english based languages and they are not great for black boxing i.e you have to know the domain of your problem because relying on libraries is impossible at worst and not any better than python or java at best. That being said I find them more scrutable than most langauges partly because of the tersity. And partly because of the limited vocabulary. You can look up unfamiliar operators very easily in array languages because they all come with multiple (some more for reference some more for learning) easy to go to places to do so. But more importantly there really are only so many so you can learn them all (in the same way you already learned your numbers + - 3 %, and so on) once you do you dont feel the need to look up 6 or & or + mean you just know them. In contrast in a language like python or javascript im constantly looking up how things work because there are just infinitely more things the source code of which is often hard to get to and when you find it it is very long (and therefore (for me) hard to read). When I see an array function I actually can scrutinize them when I see a python function I need to hope that its simple and named in a way that makes automatic sense to me or give up and look it up somewhere else (in docs say).
That's fair. My remark was a bit of a tangent, borne of frustration over years of trying to read papers relevant to my interests where the juicy bits are all written in math notation and therefore inaccessible. I have to go track down some open-source implementation of the idea and read that to understand what the paper is trying to say - any programming language at all, even one I've never seen before, will be easier to understand than the original symboldegook.
I can imagine that it's a much different situation with array languages, where the notation is actually learnable, because it is defined and documented.
I just fail to see the point. I could see the use for some convenient functions for array manipulation, but why not just implement these as a library in any existing language?
>This allows one to think faster and further than they could encumbered but a heavier syntax.
How does the programming language limit your ability or speed of thinking, lest when the fundamental data types and operations are the same? The hard work is always knowing what to implement. Saving some keystrokes for reversing an array or whatever other array manipulation is hardly a game changer.
It's not about saving keystrokes, it's saving brainpower and effort when reading, writing, and modifying code. Instead of thinking about control flow and nested loops when doing multiple complex operations on an array, you're thinking only about the array operations. Abstracting away the loops and control flow frees the programmer from the most tedious and error-prone parts of programming.
> library in any existing language
An example of this is APL.jl [1][2]
It seems more of a proof-of-concept than a real implementation though - at least, the APL wiki calls it a "toy dialect of APL" and says that it "works on a minor subset of APL". [3]
[1] demo: https://nbviewer.org/gist/shashi/9ad9de91d1aa12f006c4 [2] repo: https://github.com/shashi/APL.jl [3] https://aplwiki.com/wiki/APL.jl
This looks more like an interpreter. What I mean is just take the symbols in Klong and write them as methods on arrays. Sure the syntax won't be the same, but does that really warrant a whole new language?
Why not a whole language when so many problems can be easily reduced to these few methods?
It's worth noting that almost all array languages are interpreted, and iteratively constructing a program in the interpreter is common. This style would be painful in a more verbose and lower-level language but works great for ultra-high-level array languages.
I think there is literally nothing I could say that would change your mind. You've already decided what you think. There are a number of benefits but none that I could write out and have you someone who is uninterested immediately take my word for it and go home a fan. But I'll try to answer your (probably rhetorical) direct question. "How does the programming language limit your ability or speed of thinking". Again tell me how it is you do difficult math? Do you write out english or do you work with notation that makes it easier to feel and calculate your way through a problem. if you wanted to write a program in a new domain do you honestly think you would come to the same level of understanding of the topic at the same speed if you use assembly vs python. Yes the hard work is knowing what to implement; arrays languages help its users know what to implement. Ultimately, these are all just claims I can't prove to you what experiences you will or wont have if you learn the languages. You wont just believe and you shouldn't just believe me. If you are interested, learn more and try it out! (theres the apl and k wikis, a discord called the aplfarm a podcast called the arraycast etc.) If not just write array languages off and move on.
Most programmers don't do any math at all, so maybe this is just a niche thats not relevant to most of us, but to answer your question:
If I am thinking about any problem, its outside the scope of any programming language in the first place. My point is, modern functions already make array manipulations simple enough. Even if you're doing something like coding LLMs from scratch, numpy, list concatenations, list comprehension, lambdas, stream/map/reduce all exist and its not nearly an issue to implement them, as is the case for writing assembly vs python.
The prime example in python for example looks like this: all(x % i != 0 for i in range(2, x)) This pretty much does the same operations in the same order on the same fundamental data structure, so I just don't see what's fundmenetally different about the Klong way of thinking.
Anyway, I don't mean to argue, if it works for you great, I wish I had something new
My point with math is not that this only applies to fundamentally math like things but that these languages do for programming what the math notation does for math problems for me. "if i am thinking about any problem, its outside the scope of any programming language in the first place" yes I felt this way too before I learned an array language. Sorry that was a rude way to put that but I do genuinely mean that. Array languages help me solve problems I wouldn't know how to solve otherwise. that python code looks suspiciously full of symbols and one character variable names :). Maybe it would be easier like this: all(exes modulo index not equal zero for index in range(two, ex)).
one of the biggest differences between the k way and the python way too is actually limitation. in practice python has a bunch of stuff that doesnt fit too well together necessarily but that you can put together to make whatever you want often without much knowledge underlying what youre using (like how one can make a neural network with no linear algebra knoweldge) in the array languages you have a set vocablary and only a few ways of putting them together such that you become fluent with the whole languages and you brain starts to just put whole correct functions or programs together in the way one might do with a natural language you know well. Its a great exprience and it changes how you think. HOWEVER, I wont pretend for a second this does not come at a cost. The real power comes from fluent use of a small vocabulary meaning you dont get the immediacy of libraries, IO has to be dealt with by the programmer more so than in languages where you have alot of help form libarires and frankly non algorithmic code in these languages can be really funky and rarely as good. Unless you are writing very algorithmically intense stuff imo array langagues are best suited to embedded use in another language or not at all. For you and for most people I think things like the python you've shown there works plenty well enough.
> why not just implement these as a library in any existing language?
I bet you heard about NumPy :) (Also Pandas, Polars, etc.)
Klong was among the languages I looked at when I was trying to pick a language for a project (ongoing but back-burnered at the moment). Ultimately I went for Dyalog APL, but looking at the documentation - and the great website - for Klong I found it quite... charming? If you're familiar with the array paradigm it's pretty straightforward.
Unrelated editorializing - Klong has come up in passing on the Array Cast [0] before, but I'm surprised they haven't interviewed Holm. They seem to be doing less of the "forbears tell awesome stories" episodes lately. Which is a shame because that's probably the single best sub-set of Array Cast episode types...
[0] https://www.arraycast.com/
> If you don't know any array languages, it might explode your brain. Use at your own risk!
I've been around the block, don't think it'll be a problem picking up something new
> Here is a program that checks whether a number x is prime (for x>2): {&/x!:\2+!_x^1%2}
(closes laptop and goes outside)
I mean its not that bad.
You just go right to left. 1/2 applied to x^ so x^(0.5), _ is floor so floor of x^0.5. ! creates an array of numbers up until floor of x^0.5. 2+ just adds 2 to every number, and then I lost interest in learning the rest lol.
Yeah I like the python equivalent def is_prime(x): return x > 1 and all(x % i != 0 for i in range(2, x))
I wonder what the relative performance of the two snippets (Klong and Python) is.
Not at a computer now, can't check.
There's a niche out there where this kind of technology is appreciated. I can even appreciate the technical challenges in making an array language interpreter run fast!
However, unfortunately, the notation is so terse that I can't imagine spending the time to learn this. This looks write-only.
Is there an obvious reason to prefer a k-like language like Klong, over e.g. Futhark[0] or Accelerate[1]?
[0]: https://futhark-lang.org/
[1]: https://hackage.haskell.org/package/accelerate
the terseness is magical when you are in the repl and it just takes typing 1, 2 or a hand-full of characters to try an idea you have
edit: and when you want to understand a larger program the terseness means you might be able to actually see it as a whole, in one page or screen
I can't read anything that is too far out of my fovea. If I look at a word in the middle of a sentence, I can read it, and the two immediately adjacent words. After that, the ability rapidly declines. If the next words after those two are simple like "and" and "the", I can still read them while staring at the middle word. Beyond that, I am aware that there are letters and words, but no decoding takes place. If something fits on the screen, it's nice that I don't have to scroll around, but I certainly cannot see it all at once in a semantic way, only as a picture.
It's more a matter of comfort for me than anything to fit a program in a single screen or a function with a single line - large programs and functions are significantly more anxiety-inducing for me to read and work on. I have to keep scrolling and scanning back-and-forth and easily lose my train of thought and get the feeling that I've forgotten something important.
Folding editors can help. Maybe also if there were a thumbnail of the file in a sidebar, with a rectangle representing the current viewport, that could help reduce the anxiety, by giving you an estimate of how much more is there off-screen.
Beyond that, it's part of the course. Nowadays you will not get to work on a production anything that all fits on your screen. Individual files might, but they are part of a whole that doesn't.
Self-contained programs that fit on the screen are able to do that because they reference a language, and that language is not on your screen. You learned the language and so you don't have to take your eyes off the program to look up the documentation or source code.
I wonder if these extremely terse languages might see a rise in popularity with LLMs, since they save a lot of tokens. The hard part would be training on them, since training data is not as comprehensive as JavaScript, for example.
Fun times! :)
> The hard part would be training on them, since training data is not as comprehensive as JavaScript, for example
From terse languages surely there is a lot of training data for Perl. Not nearly as terse as J, K or Klong, although.
No idea why emorning3's comment is marked [dead]. It's a good question and in fact Klong arrays are very much like S-expressions. In fact their implementation is pretty much the same, down to using CAR and CDR to manipulate them. Klong could easily be implemented as a bunch of LISP functions and macros.
> No idea why emorning3's comment is marked [dead].
https://news.ycombinator.com/item?id=44231847
It's [dead] because they were banned, not because of the comment itself. It can still be vouched for.
I wonder how much overlap there is between users of array languages and of scientific programming languages/dialects like MATLAB, Numpy, and Julia, which are also optimized to operate over arrays. In other words, do K/Klong/whatever proponents realize that there is already a huge community of people who appreciate and utilize powerful operations on arrays to do real work, but just prefer to write something like "max(diff(x))" instead of "|/--:'x"? It's almost the same number of characters and it doesn't require learning a new writing system.
"already": APL dates back to about 1966, and even K from 1993 predates Numpy and Julia. But yes, we do not live in caves and are familiar with these languages. Klong has even been implemented in Numpy, see https://github.com/briangu/klongpy.
I understand that these languages are older; I meant that in the sense that they are nonetheless still trying to recruit new users, but these potential users may already be using something that does something similar.
Oddly enough, the biggest mistake in how I presented BQN early on was thinking only APL insiders would be interested, when in fact the APLers went back to APL and people who hadn't tried other array languages or hadn't gotten far with them were were most successful with BQN. Plenty of people coming to BQN have worked with Numpy or whatever, but I don't think this has the same deterrent effect; they see BQN as different enough to be worth learning. Julia in particular is very different: I don't find that it culturally emphasizes array programming at all.
Array languages like K/Klong are fundamentally different from NumPy/MATLAB in that they're built around rank polymorphism, point-free composition, and tacit programming - not just terse syntax but a different computational model with different performance characteristics and compositional properties.
Julia is fun when used with the “array” mindset. It can also get very terse [0]
[0] https://code.golf/wiki/langs/julia
More golfing at https://codegolf.stackexchange.com/search?tab=votes&q=Julia%... (although most of these rely on syntactic tricks rather than array-language-like terseness).
The world is big enough for people to safely experiment with programming languages. I don’t think there’s any risk to Matlab/Python/Julia (and indeed, many people did and still argue that Julia is excess baggage).
I mean, sure, why not, and I'm not opposed to using array languages as a fun hobby (which seems to be the spirit of this). I just noticed that the selling points in the introduction to the manual were not very compelling to me as a Matlab/Numpy user, and since sometimes people bemoan that array languages aren't more widely used, I just wanted to say, hey we do have powerful "array languages" that imo are strictly better on things that matter for most real work, so it's not surprising.
To be clear, you are referring to the preface to "An Introduction to Array Programming in Klong", right? Having just checked it, I find this to be a very strange angle of attack, because that section is almost exclusively about why the syntax in particular is important. Obviously you disagree (I also think the syntax is overblown, and wish more writing focused on APL's semantic advantages over other array-oriented languages). I think this is a simple difference in taste and there's no need to reach so far for another explanation.
First line of https://t3x.org/klong/prime.html
"The braces around an expression denote a function. Because this function contains a single variable, x, it is a monadic function or a monad."
I never understood that about monads, even if it's litterally their name.
A monadic function in APL-family languages is not related to monads from category theory, which are the ones you see in Haskell, nor to Leibniz's monads.
In this context it just means "one parameter function".
It looks like every apparently free variable in a Klong brace expression is actually bound as a function parameter.
This is so in basic algebra in that we can think of, say, x^2 + y^2 as a two parameter function, even without writing out the full f(x, y) = x^2 + y^2 notation with the f(x, y) head.
A two parameter function would be called "dyadic" in the jargon which calls one argument functions "monadic".
Google tells me that Klong and Lisp are not the same thing.
But can someone tell me why an array in Klong is NOT like an s-expression in Lisp?...
> If you try to use it like your favorite functional/procedural/OO programming language, you will only get frustrated.
For me personally, the sentence could be shortened to just: "If you try to use it, you will only get frustrated."
So the sentence served its purpose and saved you the frustration :)
I appreciate the features of these languages (J, K, and Klong), but I do not understand the reason why they have such a hard to read syntax. I think it is a pity; I could see myself using it otherwise. Maybe it is by design, but I do not understand it.
Here is a gentle start: https://xpqz.github.io/kbook/Introduction.html
Thanks! So here is an explanation:
> The same baseless accusations of “unreadable”, “write-only” and “impossible to learn” are leveled at all Iversonian languages, k included.
I argue that these accusations are far from baseless. Sure, I can not cite a study, but neither does he. So I assume it's word against word.
> Readability is a property of the reader, not the language.
In my view this is an oversimplification. Having a steep learning curve clearly prevents adoption. The language design actively contributes to the problem. I'm just not sure on why. Could it be that the authors of these languages do not _want_ them to be used by others?
Search for "teaching" at https://aplwiki.com/wiki/APL_conference. I count at least five papers about teaching non-APL topics using APL. The language is not only possible to read, it's designed for it.
The learning curve isn’t steep. I’d argue the opposite. K is a tiny, tiny language. Put your mind to it, and you’ll be reading it just fine in a weekend. It’s just different. It’s optimised for its wheelhouse.
You could say you enjoy toodling on the piano but don’t understand why reading music has to be so hard. It doesn’t _stay_ hard and it opens up new avenues.
I guess you could say the same about Chinese language, but many people who learned it understand it