APL deserves its renaissance too (2018)
wordsandbuttons.online
wordsandbuttons.online
> A jupyter notebook style ide+repl (maybe a bqn for of RIDE)
J terminal looks pretty close.
> libraries for common scripting tasks
There are phrases (see www.jsoftware.com), but for many tasks it seems not many libraries are actually needed.
> embedding (a la lua) in more languages, maybe even a way to compile to libs so you can call bqn code from other languages
There is a way to call C from J and vice versa; not too convenient maybe... but still quite possible. APL languages don't benefit much from compilation, J interpreter is very fast.
Is the idea because most the action is in already compiled datastructure manipulations, in the standard library, specified by the terse source?
For "one potato two potato" scalar code code with lots of branches and control flow, compiled will always be faster because each little op has overhead and a compiler could optimize it away.
A sufficiently smart interpreter or JIT could theoretically optimize this away too, but as far as I know no APL (or APL-like) language uses anything like a tracing JIT, instead they have historically focused on optimizing idiomatic expressions so "typical" code is faster.
Sorry, but this is nonsense. APL tends to spend all its time waiting for memory, because it fuses nought. And it benefits as much as anybody else from things like common subexpression elimination and loop-invariant code motion. APL implementations appear to be fast because of a few extenuating factors:
1. C compilers kind of suck, and c kind of sucks for writing fast code, yet it is the de-facto standard, so it is what things are compared to.
2. Developers of apl implementation care about and prioritise performance.
3. In comparison with languages such as python, and in particular their popular implementations, apl spends very little time on dispatch.
(I've written some about what array compilation would mean at https://mlochbaum.github.io/BQN/implementation/compile/intro...)
Regarding scans (filter is a type of scan, howbeit easier to implement than the general case), there is in general an annoying work-span discrepancy, which bodes ill for contemporary computers with their finite parallelism. I would buffer heavily here, but fusing the scan with its input allows for the use of a work-efficient implementation, spending all latent parallelism on generating more inputs.
When I speak of loops, I am including any usage of rank (incl. implicit); in this respect, apl is chock-full of loops. Some loop optimisations may be obviated, of course, because of referential transparency, but others arise in their place. Take for instance some recent work[0] done on futhark: rather than parallelise an already in-place algorithm, they had to in-place an already parallel algorithm!
Two more points:
A problem may be bound by memory latency. I spent some time tuning j's I. recently, and it does many searches in parallel (4 for a small search space, 12 for a large one, iirc), but it is still bound by latency. If I could fetch a pivot corresponding to the first cell of y, and then generate the next cell while I wait, I would make better use of resources.
A compiler results in more transparent performance characteristics. When I target an interpreter, I must write my idioms and special combinations in exactly the way it expects, else nothing will happen; a compiler will care much less about exact phrasing. Similarly, like I mentioned, you get licm and cse for free, rather than needing to do them by hand.
0. https://futhark-lang.org/blog/2022-11-03-short-circuiting.ht...
Some of the problems you mention, especially special combinations, can be addressed by a bytecode compiler that ultimately defers to an interpreted VM.
The binary search interleaving seems like exactly the kind of thing that APL interpreters can do to close the gap with compilers. "generate the next cell while I wait" sounds difficult in general: instruction reordering only goes so far, so if the binary search loop needs many iterations, then only part of it can overlap with other code (barring some compiler intervention that I'd categorize as fanciful if the loop length isn't known). That other work could also be polluting the cache.
Your binary search work is definitely interesting; I found the code and will be studying it as this is something I've been wanting to address better in BQN. Mind if I email about this? I implemented a different solution to high latencies for large searches in Dyalog, which is to partition the array y (searched-for values) by a single pivot from x and recurse. See the last paragraph at https://mlochbaum.github.io/BQN/implementation/primitive/sor....
It's not really clear to me what this is measuring, and whether that thing is interesting. I care about throughput as measured in widgets per unit time, not instructions per unit time; the contribution of a compiler may not only be in instructions per unit time, but also instructions per widget.
> Some of the problems you mention, especially special combinations, can be addressed by a bytecode compiler that ultimately defers to an interpreted VM.
Sure. But aside from implementation effort, that seems monotonically worse than a compiler targeting machine code.
> if the binary search loop needs many iterations, then only part of it can overlap with other code (barring some compiler intervention that I'd categorize as fanciful if the loop length isn't known)
What interventions? FWIW I think the main limitation is (architectural) registers (plus rob/rename, of course), but you can balance around that by putting multiple _dependent_ search iterations, and leaving enough time for them all to finish.
Also: I think it's probably good to have at least a rough idea of how many iterations things are going to take, and am vaguely planning to specialise on order of magnitude of each dimension (plus exact value when small). Knowing how big things are also gives you a fairly good idea of what is going to pollute cache (conservatively assume that random accesses are uniformly distributed) and by how much.
> Mind if I email about this?
Feel free! elronnd@elronnd.net. FWIW I think the gather hammer, where supported, is probably ideal--I benchmarked it, and it lost, but I was on AMD hardware at the time, which is quite abysmal in that respect; intel seems to be much better, especially with avx512--and that leads to much more straightforward code.
> I implemented a different solution to high latencies for large searches in Dyalog, which is to partition the array y (searched-for values) by a single pivot from x and recurse.
I figured it was doing something like that. Was thinking about implementing something similar, but vaguely hoped that if the buffers were large enough and I could keep them filled, it would be possible to avoid the overhead of partitioning and of scattering results. Also the option, depending on relative sizes, of preprocessing x, producing e.g. a b-tree or eytzinger. Fairly low priority, so I've not yet looked too closely.
I've spent far too much time working on an APL dialect that allows you to combine APL with imperative structures at the same time. I really need to document it better though. https://aplwiki.com/wiki/KAP
Then there is April, which is a very neat version of APL that is implemented in Common Lisp. It allows you to miss Lisp arrays with APL arrays, giving you the best of both worlds. It's very functional even now: https://github.com/phantomics/april
And of course, BQN is a new language that takes a lot of the good ideas from APL but also changes a lot of the symbols. It's a very nice language: https://mlochbaum.github.io/BQN/
https://github.com/phantomics/april/ and yes it is used in production©!
> What pushed the development of April really is that April is used by a hardware startup called Bloxl (of which I am the CTO). There are other users but Bloxl is the flagship application.
https://www.arraycast.com/episodes/episode23-andrew-sengul
Bloxl in use: https://user-images.githubusercontent.com/3721004/159686845-... See also the ELS conference 2022.
Mistakes were made.
https://www.youtube.com/playlist?list=PLrwpzH1_9ufMLOB6BAdzO...
Back then, computers were so limited relative to human capability that this was still a good thing. Those days have gone. The bizarre syntax of APL has had its day. Its powerful array manipulation primitives can easily be brought forward into a language with modern syntax, and haven't they? In my company there is a lot of Matlab usage but I'm personally not knowledgeable.
Kind of. The languages that one might expect to do this (Julia, R, NumPy) have picked out a few things from APL in an inconsistent way, leaving a lot as well. For example most are missing the generalization of prefix sum that APL calls "scan". So in [0], Conor was able to translate some code to every language in the APL family but not yet any outside of it. Another one, I don't think I've ever seen Replicate[1] outside the APL family. It's a generalization of filter to take an arbitrary count instead of 0 or 1 that's often useful if you know about it.
[0] https://github.com/codereport/array-language-comparisons/blo...
"even C#" seems to imply you have less obscure examples than a function in a Linq package, is this the case? I admit I've never looked into Linq but I do see it come up in array language discussions sometimes. It's possible it has a more APL-like philosophy for a slightly different use case. The other difference is that APL uses a function on two arrays, which is nice because you can easily filter based on, say, the previous element.
EDIT: No, the C# function seems to only do the mapping and concatenation and doesn't even take a number of copies, that's really not the same.
Excel has SCAN.
np.repeat(list("abcd"), [2,1,0,2])
is equivalent to the first example in the link. replicate(inds, v) = mapreduce(((i, n),) -> fill(v[i], n), vcat, enumerate(inds))
I agree with the spirit of your point though. Having operations like this as part of your 'alphabet' can be a really powerful thing. That's why I think APL is really well suited to being a domain specific language embedded in a language like julia. Shashi took a stab at this a few years ago, but it'd be nice to revive it: https://github.com/shashi/APL.jl rep(c("a", "b", "c", "d"), c(2, 1, 0, 2))
c("a", "a", "b", "d", "d")The more thoughts you can fit on a page, the less taxing it is for your working memory.
We try to use abstraction - libraries, DSLs, even lowly functions - to tame ever more complex problems, but anyone who's had to debug a dependency of a dependency is painfully aware of the cost of leaky abstractions.
In R I often use the data.table library and the style of programming that encourages feels similar to how J made me think.
> modern syntax
is mostly awful.
A ⌊.+ B
will produce a new adjacency matrix (call it C) where each c_ij is the minimum traversal cost from node i to node j. For example, if A represented driving times from all cities in NY state to all airports in NY, and B represented direct flight times from all NY airports to all CA airports, then our result would be the minimum travel time (ignoring parking and security) between any NY town and any CA airport.The sequence `⌊.+` is an inner product chosen specifically to achieve this effect, with addition where multiplication would normally be, and ⌊ (min) where multiplication would normally be.
Notice that it took me longer to give this under-caffeinated explanation of what is going on than to write the code.
Inner[Min, A, B, Plus]
where B = Transpose[A] ?Sorry, it is early for me too. I am wondering if there is a mistake here. Do you mean that addition is where multiplication would be and min is where addition would be?
The regular inner product would be
C_ij := \sum_k A_ik B_kj
and the modified one is C_ij := \min_k (A_ik + B_kj)
?Note that this pseudo-code is very nearly valid Julia code (with my package):
@tullio (min) C[i,j] := A[i,k] + B[k,j]Python does not have this terse a syntax, but it gets very close with multiple bindings to the SuiteSparse GraphBLAS Hypersparse graph processing libraries, which intrinsically supports sparse graphs and a very large number of operators, including the tropical min/max ones. Suitesparse doesn't provide syntax (that's the easy part), it provides the hard part, sparse and hypersparse data structures and very complex dynamic, parallel graph processing optimizations including JIT compilation of GPU accelerated operations.
Here's a notebook that shows your shortest path example using Python and the GraphBLAS. While it's a trivial example, it can scale the the largest graphs possible to use today using SuiteSparse:
https://github.com/Graphegon/pygraphblas/blob/main/demo/Intr...
NB: I should clarify I'm not advocating for Python's syntax in particular vs APL, I'm saying that syntax is not the hard part of any particular problem, especially when it comes to sparse graphs. There are also other binding to GraphBLAS like Julia that are quite nice. I do appreciate that APL does elgantly permit the notion of graph operations with linear algebra.
C_ij := \min_k (A_ik + B_kj)
would work to give all pairs shortest path, since in floyd-warshal the results of C[i][j] at iteration k depend on C[i*][j*] for k-1 being computed, which is not true for the above where C_ij can be computed independently of all others.It seems like it _is_ possible to easily express APSP via an inner product with (min, +), but it's less efficient than floyd warshal. Whereas floyd warshall asks "What's the shortest path from i to j using vertices in {1..k}", if you instead ask "what's the shortest path from i to j of length at most k" and then use repeated-squaring you can get the answer in n^3 lg(n). See
http://users.cecs.anu.edu.au/~Alistair.Rendell/Teaching/apac...
https://cse.buffalo.edu/~hungngo/classes/2004/531/notes/floy...
https://resources.mpi-inf.mpg.de/departments/d1/teaching/ss1...
https://www.cs.utexas.edu/~ecprice/courses/randomized/fa15/n...*
> learning all the alien symbols is a one-time investment
No one time investment is needed if you want to learn J.
And yes, it does teach you to think in a new way. I am not kidding.
You can see the plethora of (mostly free) books available at the website [0].
Learning J has given me "enlightenment" at the same level The Little Schemer has given me.
(I don't recommend APL to anyone as you need to learn and painstakingly slowly insert those symbols. If you want to learn array thinking, go straight to J. Why waste time and headspace with APL symbols?)
Most people don't know about J, but know about APL because of those weird symbols.
I agree with your thoughts that not everything should be ASCII (and this is what many comments on this thread don't see), but don't reach the same conclusion as you do.
Well, not anymore. But I will prefer ASCII over glyphs any day.
I have learned symbols in Math, and I keep learning newer ones.
It finally comes down to _RoI_.
The vast and tremendous return I get from non-ASCII characters in Math (and have gotten for decades)- I will not get the same amount from APL. It's as simple as that to me.
The J for C Progammers author divides loops in, I believe, 7 use cases and for that one he ends up using "an adverb" (a high order function) he wrote himself? Why? Because the language default adverbs don't support it.
In comparison, Q had very good support for that. Q also doesn't require learning symbols.
I learned J the same reason I learned Scheme- to expand my mind, and perspectives.
And I definitely would not want to use J for solving real-world problems, but I would definitely state that there are a lot of ideas in J-like languages that merit being looked into and being taken from there into modern Deep Learning frameworks.
And of course, it extends your mind.
I don't understand the "{J,K,Q} don't require you to learn new symbols" argument. You're learning a mapping between symbols and functionality, not literally learning to recognize the lines and curves that make up the glyph.
"reverse" is `|.` in J and `⌽` in APL. It doesn't seem obvious that the J mapping is easier just because I've seen those characters in other contexts.
It does take a little work to learn where they live on the keyboard, but that doesn't seem like a huge barrier to overcome. The live editor on the BQN site shows a list of glyphs and hovering shows you where they are on the keyboard. You just prefix with `\` to type them, so you don't even need any custom keymap.
(https://news.ycombinator.com/item?id=17176147 4 years ago)
With apologies to Phillip Greenspun.
https://philip.greenspun.com/bboard/q-and-a-fetch-msg?msg_id...
The influences came from Standard ML and OCaml, primarly.
F# started its life as OCaml.NET.
If it's licensing/a desire to use open-source software, perhaps taking a look at its close relatives of J, or BQN, would be reasonable?
* Dyalog https://www.dyalog.com/download-zone.htm * J https://code.jsoftware.com/wiki/System/Installation/J903/Zip... * BQN https://mlochbaum.github.io/BQN/index.html
All of the languages and implementations have their differences, but they are all driving toward the same ultimate goals.
GNU APL is closely following the APL2 standard [2], Dyalog has lots of (proprietary) extensions.
APL does not have its roots in the FOSS world, all the more the efforts to provide and maintain a powerful, free option here are to be supported. It is not self-evident that there are always free software alternatives available.
I'll pass, but you do you.
> Learning k9 means code like {x@(!#x)+\!#y} is clear and actually prefered to something much longer and verbose.
https://estradajke.github.io/k9-simples/k9/index.html
All I could think of was Abelson/Sussman's evergreen quote from the preface of SICP:
> Programs are meant to be read by humans, and only incidentally for computers to execute.
Where I have seen bakeoffs and largely failed attempts to replace, the challenge is the number of vendor & open solutions you need to cobble together to replace all the use cases that KDB supports. Every year it was a slightly different combination that didn't really cover all the bases.
To replace KDB in many of these large use cases, you need - a fast columnar PB-scale database, an efficient on-disk store, a fast in-memory cache, SQL support plus with expressive query language additions for time series operations, an event bus, a stream processor, and a programming language to write more complex applications close to the data.
A lot of the newer cloud-centric offerings are more about massive parallelism/scale than about pure single thread/individual request-response performance.
This is great for the vast majority of CRUD apps with millions/billions of users.
It's even great for some financial "backtesting" type use cases where you can kick off large
It generally isn't sufficient for many of the real-time financial use cases of doing ad-hoc analytics on billions/day datasets with expected responses in ms.
The biggest complaints are its expensive, and the devs are expensive. On the other hand you usually don't need as much hardware or dev staff to support it.
Sounds like ClickHouse. And we see kdb slowly start being replaced...
You just mentioned mathematical articles where the math expressions are a minority of the text, right?
> But mainly the point is about the language itself and the prioritization of terseness over unambiguity and intuition.
Math notation had - and keeps having - reason to be terser than plain text. Same for APL - which started life as "Iverson notation".
> Good mathematical notation strives for the latter, not the former.
Don't you think APL is a pretty good mathematical notation? If not, why?
Yes, mathematical notation is terse (mostly to make manipulations and computations easier to type) but people take special care to avoid ambiguity or too much context dependency, and also don’t try to introduce symbols for everything.
Which is fine. Not every language needs to do everything. Horses for courses.
https://forums.fast.ai/t/apl-array-programming/97188
I've programmed in APL last millennium. It is hell.
Something like the DuckyPad[0,1] might work for that as well. I haven't tried using mine for APL or anything like that, but it's been great for use as a "Zoom meeting control", numpad, and MacOS shortcut pad.
[0] https://github.com/dekuNukem/duckyPad/
[1] https://www.tindie.com/products/dekuNukem/duckypad-do-it-all...
Ahk can override keyboard button presses with just about anything and you can use a layer key as a modifier
But I'd really like a language that comes with its own keyboard :)
I mean, other people should be able to edit my code.
Emacs lets you display arbitrary text as any symbol you want, and you can also map your keyboard to generate that text with any keystroke of your choice.
So the result is the same, without needing language support for the symbols you want to use.
I've done this with the lamba symbol and symbolic logic symbols when editing LaTeX files in emacs. It works great.
I haven’t had the audacity to use it in production code, but it’s interesting to play around with and great for quick note taking or hacker news comments. (Sadly I’m on my phone right now to not make use of it for this comment)
But we don't do that. Because the brain needs redundancy. Ditto source code.
Let's say you're at work, and you casually mention to your team something about APL, ATS or Agda. How many were excited about it? How many did roll their eyes? Yeah, I thought so.
Is it still pretty cool? Yes I think so.
APL deserves its renaissance too - https://news.ycombinator.com/item?id=17173283 - May 2018 (118 comments)
(Reposts are fine after a year or so - https://news.ycombinator.com/newsfaq.html - especially about APL.)
For the right use cases, it's unbeatable. Sure, you probably wouldn't want to write an OS kernel in it, but anything that reads a bunch of data, mashes it up, and spits out some result, APL is a hand-in-glove fit. And with modern SIMD processors, APL really screams.
https://xpqz.github.io/learnapl
https://xpqz.github.io/cultivations
Drop in on https://apl.chat if you're interested.
You can try it for yourself -- NumPy is a fair "Iverson ghost" -- APL without the symbols: it has a similar enough array model, and most of the APL primitives as functions or methods. APL lets you express linear algebra in a very natural way. Doing it in NumPy is much more convoluted.
Or try Rob Pike's (of Go fame) "ivy" -- his attempt at an APL-with-words (https://github.com/robpike/ivy).
"quote fast unquote is not relevant hyphen the runtime would be just as fast if the code was written in plain words period code size is also irrelevant unless you apostrophe are called initial capital elon musk period the only claim left is that it apostrophe s a productivity boost comma but i just can apostrophe t see how a language that needs a special keyboard to be written can be written more productively than actual words comma especially with modern initialism ide s period"
because symbols are useful. And people don't have a problem with peppering code with chorded symbols like () ++ {} : <> ? without demanding that they be turned into words because words are easier. In fact people struggle when making new languages (Rust, C# new versions) to find more symbol combinations, reaching for things like Python's triple quote strings """ """ and :: and ""u8 and so on.
There's nothing inherently better about shift-2 shift-2 shift-2 shift-2 shift-2 shift-2 than altgr+i
Why aren't the common operations of transforming collections short, sharp, and getting out of your way? Why are they ceremonious "map a lambda which takes a parameter with a name and ..." when you don't need that.
Unfortunately, given that the program is going to be read by people, what we care is about what the beholders say.
> just because I can't read Japanese does not make Japanese unreadable
A nice comparison: Japanese is indeed harder to read than other non-symbolic languages. Symbols are harder to recognize because there are far more of them than letters in alphabets (latin, greek, cyrillic). For example, do you think it's easy to recognize the difference between 陳 and 陣? The more symbols you have, the harder they are to process, be it Japanese or APL.
Yes, because it's their native language. Doesn't say anything about the difficulty of it. My mothertongue is Spanish and I'm fairly adept at using it, and still doesn't mean that some aspects make it harder than other languages (verb conjugation, gendered nouns).
> or referencing well-known mathematical counterparts.
As a mathematician, other than the very basic symbols, most of the ones used in APL are not familiar, or are used in different contexts. For example, × is cross product and in APL is regular multiplication, ⍟ is logarithm even when "log" is what's used in math, and "⊥" looks to be polynomial evaluation when that's usually the symbol reserved for orthogonality.
> Counting the elements in an array is ≢
Funnily enough, that symbol is "not equivalent" or “not congruent” in math. Never would have though it refers to the symbols in a paper.
Isn't it the other way around - Iverson invented this symbol for this purpose and the standard mathematic notation adopted it?
Japanese readers do indeed take in information slightly more slowly than average, but not as slowly as Finnish readers -- a language with 26 latin-based characters.
[1] https://iovs.arvojournals.org/article.aspx?articleid=2166061 (summary) https://irisreading.com/average-reading-speed-in-various-lan...
I think this is a huge part of what makes it hard for people. You have to read denser code slower. APL code can easily have 1/10th of the characters when compared to code in popular languages. If you read at the same speed then you're reading... ten times as fast. That's a bit much to ask. You could read a five times slower and you're still covering information at twice the speed.
Do you have a study that confirms that kanji are harder to read for Japanese speakers than romanized transcriptions?
In English or Spanish, we also don’t read individual letters to reconstruct the words that they represent. We read the shape of each word. This is why “floor” and “flour” are harder to tell apart than “floor” and “flower.”
But the important thing is how symbols/words are processed. For any given concept, we might have the symbolic representation, the auditory representation and/or the pictoric representation. The good thing about words is that, even if you haven’t seen the written word before, it maps to the auditory representation (more or less depending on the language). Kanji doesn’t (in fact, the same symbol might map to different “words” and sounds) and it’s not a very precise pictoric representation either.
This is not to say that Japanese is impossible to learn or much more inefficient. Just that it makes it harder to learn and read. In a similar way other languages have traits that make them easier or harder. For example, English is harder because of the inconsistent mapping between writing and pronunciation. French is harder than other languages because of the number of vowel sounds and how important it is to make them different. Spanish is harder because of gendered nouns and the fairly complicated conjugation norms for verbs. Of course native people get used to those things, still doesn’t mean they don’t make things harder or easier.
By the way, you might know this, but if a Japanese speaker doesn’t know a kanji, they are not at a complete loss. Words often consist of multiple kanji so they can infer from the meaning and possible pronunciations of the other kanji in the word. The context in which the unknown kanji appears helps too. And in literature aimed at young readers, they often also show the pronunciation written next to more unusual kanji (furigana). All of this is less relevant to APL though.
And that’s just in math, where there isn’t as much symbol density as in APL and where symbols don’t depend on context too much (it’s usually not a good practice and avoided if possible to have the same symbol having very different meanings depending on the context).
I wonder if something that might be a way forward, similar to how lots of imperative languages now have language constructs that makes it easier to do functional programming in them: steal enough from the array languages to make other languages less bad. Or maybe that's what NumPy and Julia already are, which also would show the limitations of that approach. I dunno, I've read about array languages out of theoretical interest but never actually programmed in them.
New language designers will have to defend why they don't have array language features rather than why they do.
I've never tried any of the Iverson-verse languages but the non-ascii inputs seem daunting and cumbersome.
I’ve always hoped someone would make an APL for iOS and Android. The code density and use of symbols seems like a good fit for small touchscreens.
For example, the original use of APL (before it was called APL and before anyone had implemented it as a programming language -- the reason Iverson joined IBM) was to specify the IBM 370 machine architecture.
In other words, it was being used to document how the CPU worked. And it was impressively successful there, distilling a large body of documentation into 2 pages.
This reduction in cognitive load, describing machine structure, is what made it popular back then. And this is what motivated the effort to implement it as a programming language.
(Also, if I understand correctly, there's also a relatively short and direct step from APL to the initial implementation of SQL.)
Then "Iverson joined IBM Research in 1960 [...] he was allowed to finish and publish A Programming Language and (with Brooks) Automatic Data Processing, two books that described and used the notation developed at Harvard. [...] At IBM, Iverson soon met Adin Falkoff [...] Chapter 2 of A Programming Language used Iverson's notation to describe the IBM 7090 computer. In early 1963 Falkoff [...] proceeded to use the notation to produce a formal description of the IBM System/360 computer then under design."
- https://en.wikipedia.org/wiki/Kenneth_E._Iverson#Harvard_(19...
I admit it was kind of cool to be able to operate on whole arrays at a time, but nowadays I can do that with Python's numpy.
https://duckduckgo.com/?q=aaron+hsu+apl&t=ffab&iax=videos&ia...
I used APL professionally for about ten years (early '80's to early '90's) for a range of applications spanning various business applications, industrial automation and DNA sequence analysis used in the Human Genome Project. The language is/was fantastic. It truly is a tool for thought.
How about the funny symbols?
I see this type of comment all the time. If you think this way, you lack context. The notation is an important element of APL's value proposition. You cannot understand this by watching an APL video on YouTube or running through a tutorial.
I equate it to something like using vim. People who have casual contact with it absolutely hate it. Those who commit and develop the skills and mental automation have a very different perspective. From that context, someone saying "vim's cryptic keyboard commands and states are horrible" sounds, well, I'll be kind, uninformed.
And yet, my first sentence implies I think APL does not deserve to exist. Which is it?
I firmly believe the future of advanced types of software engineering will require a form of notation in order to effectively communicate and describe computational solutions. What comes to mind is AI/ML. I think APL needs to mutate and evolve into being the tool that is best-suited for solving complex AI/ML problems. If this can happen, the notation will be critical and just as important as it is in mathematics or music.
I think the issue might be that we don't yet know enough about this evolutionary stage of AI/ML to understand what kind of programming notation we might need to invent. This isn't well defined at all. For the most part, AI/ML is exactly where it was in the 80's and 90's. We have faster computers with massive resources. Yet, if you go back to books on AI dating back to the 80's you will be surprised to learn we haven't really invented much in the last few decades.
This three volume set on my bookshelf is a good reference dating back to the early '80's:
https://www.sciencedirect.com/book/9780865760899/the-handboo...
In fact, if you read through it you'll discover just how much was done in the '70's and '60's.
So, yes, I would not use or recommend APL for any modern project. It's a liability from an ROI perspective. In addition to this, the pool of capable APL software engineers is microscopic. That is a huge problem. APL does not make business or technical sense and cannot compete with modern tools, their libraries and the large pool of capable programmers who can use them.
I don't want my programming language to be as terse as possible. I want it to be easy to read and maintain. I don't see how APL is a step in the right direction at all, and IMO should just be relegated to the dustbin of history as a failed experiment.
Also, once you understand the rules of these languages when parsing expressions (which is always right-to-left unless the case of a parenthesis) and all the symbols, readability become less of a problem.
As for maintainability, well, it kinda depends on you and whoever is going to maintain it.
I do agree that the arcane symbols of APL is a minus, though. Which is why languages like J, K and Q are born: to make APL ASCII-friendly.
Generally speaking, this seems to me like a comment from someone who doesn't give APL more than a cursory look. And if that relates to you, please, try APL, or any other languages in the family, just even once. You _may_ change your view about it.
This is a very limited view about readability. Of course, once you get used to anything, it is more readable. But if most programming languages have moved away from symbols other than the standard ones precisely because symbols are a readability problem (even some languages like Python have and/or/not instead of &&/||/!, and those are pretty standard). It's easier to read "mod(1, 3)" than "1 % 3".
> As for maintainability, well, it kinda depends on you and whoever is going to maintain it.
Again, putting these issues on the people is missing the point of the discussion. Does the language incentivize the creation of easily understandable, fixable functions? Is it easy to detect and fix bugs? For example, assembly is harder to maintain than Python because a bug in assembly is hard to find, possibly complicated to fix because coding in assembly isn't really that easy... on the other hand, a bug in Python probably shows up as an exception even, that tells you in which line of code it's crashing.
> Generally speaking, this seems to me like a comment from someone who doesn't give APL more than a cursory look. And if that relates to you, please, try APL, or any other languages in the family, just even once. You _may_ change your view about it.
Honestly, J/K/Q/APL make it really hard to give them more than a cursory look. And the problem is that I've never seen a really good argument to do more than that. For example, first time I saw Haskell, it was hard to pick up, but at least I saw value in the proposition of immutability, pure functions, etc. Not for all use cases, but at least for some. I haven't given Go more than a cursory look but, again, the idea of a compiled language with GC and memory safety looks cool. I've never seen the value proposition of these family of languages other than "people who like them say they like them", and by the looks of the comments I don't seem to be the only one.
I think the difficulty of this is overstated. My kids are learning to read Armenian and English at the same time. 38 Armenian letters + 26 English ones, each with upper and lowercase versions. If a 6 year old can do it, you can learn a couple of new glyphs when programming.
> Honestly, J/K/Q/APL make it really hard to give them more than a cursory look. And the problem is that I've never seen a really good argument to do more than that.
It's a little disingenuous to claim that something you've never tried to do is too hard and has no value.
> Does the language incentivize the creation of easily understandable, fixable functions?
Lol, that is literally the point of them.
I've been really enjoying https://www.arraycast.com/ in which enthusiasts from several different Iversonian Array languages talk about how array languages enable them to solve problems differently.
I have my degree in mathematics and I've used my fair share of symbols. It's been a consistent finding in articles, books, classes and peer conversations that symbols are not that optimal. Inventing new symbols, or overusing them is frowned upon because they don't really make things easier to understand and can sometimes be a cause of confusion.
> It's a little disingenuous to claim that something you've never tried to do is too hard and has no value.
I'm not saying "it has no value", I'm saying that I've never seen a good argument to actually invest time in them. As I explained, other languages have clear value propositions. In J/K/Q/APL , the value proposition tends to be a vague "I like it" from people who like it.
> Lol, that is literally the point of them
Yes, 2_&{&/x!/:2_!x}'!R is very understandable.
> I've been really enjoying https://www.arraycast.com/
Offtopic, but I really dislike how so many information out there is the inaccesible format that is "podcasts".
Just as much so as սուրճ or コーヒー or קפה.
> Offtopic, but I really dislike how so many information out there is the inaccesible format that is "podcasts".
I can't think of a better format for what they are trying to do with the ArrayCast. It's not teaching people array programming, just a conversation between people who are proficient in it.
What do you think makes podcasts inaccessible? For example, I often recommend https://soundcloud.com/lambda-cast to developers looking to understand functional programming. The conversational approach works well because some of the panelists are being taught these concepts for the first time and they ask great questions. There are plenty of books and articles on the subject, but conversational audio is a wonderful supplement.
But far less than the equivalent code in, say, Python, or C, or any other language. That's the point.
> What do you think makes podcasts inaccessible?
Lack of visible, searchable structure and the requirement of audio (in those that don't have transcripts, which is a lot of them) to get the information.
The (roughly) equivalent python is filter(lambda x:all(x%i>0 for i in range(2,x)),range(2,R)) - is this really that much better? (yes if you know python, no if you know k)
From Wikipedia page of K programming language https://en.wikipedia.org/wiki/K_(programming_language)
> filter(lambda x:all(x%i>0 for i in range(2,x)),range(2,R)) - is this really that much better?
You don't need to know Python. Filter is probably doing a filter, "lambda x: ... " looks like a lambda function, for looks like a loop... I am 100% sure that, without any language knowledge, the Python version is far more easy to understand.
I will (maybe) agree that the python is easier to understand without any language knowledge - but that does not mean the K is not understandable. If you know K, it is understandable, and knowing a language seems like a pretty low bar for understanding it.
Well, of course, if you’re always practicing the same thing you’re unlikely to forget it. That’s not always the case, though.
> the symbols are distinctive anyway so that's not really a real problem.
Really? From that toolbar alone I’m seeing empty circle vs slightly smaller empty circle, a lot of symbols with/without a dash or umlaut, dot and comma… seems pretty easy to get a lot of those confused or misread.
I feel like in general, you're making a lot of (fairly reasonable) assumptions about what programming in an array language is like, but they aren't really the case (as lots of other people have tried to explain). Without really trying it out, I'm not sure how someone could convince you otherwise, so there's a bit of an impasse.
I think you should listen to what people are saying and have said in the past though (https://news.ycombinator.com/item?id=33640275, https://news.ycombinator.com/item?id=22524918) and trust that for some people who do learn array languages, they do find it useful + productive, and a lot of the things you've raised are not issues in practice.
And I think there’s a lot of implicit bias when people who like APL say it’s perfectly readable. Given how readability hits you in the face first thing when you see APL and how it’s not a widely used language, only the people enthusiastic about it and willing to overlook the readability issues will end up learning it. Of course they don’t find issues in practice, if they had issues with that they’d have probably abandoned the language quickly.
> and trust that for some people who do learn array languages, they do find it useful + productive, and a lot of the things you've raised are not issues in practice.
I’m not saying it isn’t useful or productive. That’s not the discussion. The point is that they’re languages that they’re hard to use and hard to read. I don’t see how it’s such a controversial point.
For example, I like LaTeX a lot. I’ve done quite a lot of things with it, it’s been very useful and I’ve been very productive with it. I have no problem reading that code. But the fact that I have no problems doesn’t mean there aren’t actual problems with LaTeX. LaTeX will always be hard to read and quite a bit messy no matter how used I get to it.
It's not like some people are magically born with the ability to read APL (or anything else), and learning it isn't a matter of 'overlooking the readability issues', but rather realising the 'readability issues' are a false assumption. There's not 'bias', there's just experience.
That is why "they’re hard to use and hard to read" is 'controversial', because it is just not true.
Do you think all people who decide to learn it anyway end up with the same conclusions?
> That is why "they’re hard to use and hard to read" is 'controversial', because it is just not true.
So things like symbols having different meanings depending on number of arguments, prefix notation making the arguments of functions/operators stand out less, making it reading right-to-left (which is different from what you usually read - that brings the fun question of whether APL is left-to-right in Arabic countries), or having to know extra symbols that aren't used in other contexts... All of those things are not real?
I come back to the LaTeX example because to me that's very similar. I get when you say "I don't find APL hard to read/understand/work with" because I feel the same with LaTeX (even though it's not as obscure and "alien-looking" as APL is). I write slides in LaTeX faster and better than what I could do with Powerpoint. But that doesn't deny that there are a lot of things in LaTeX that make things harder, even when those are part of the core and when removing them would mean removing good things about the language too.
> So things like <APL things> are not real?
They are real, but they are not issues for anyone who has tried APL at all.
Advent of code is starting soon, I'd recommend that you pick an array language and give the first couple of problems a go in it - even if you don't like it, at least it would save you from making yet more uninformed comments next time an array language article is on HN (and save array language programmers worldwide the pain of reading them).
https://www.dyalog.com/uploads/documents/Papers/declarative_...
I'm not saying APL doesn't have those features. I'm making examples of languages that have a clear value proposition. If APL is big on immutability and pure functions, then why use APL vs, say, Haskell or Clojure? Same with the "where is the error thing", I was explaining why maintenance isn't just a "depends on who maintains it" thing, in fact the example languages were assembly and Python, nothing to do with APL.
This is literally "people who like it say they like it". It's like saying that the value proposition of Python is having list comprehension, when that's just syntactic sugar.
And no, it's not just me, you just have to take a look at the comments or even the OP. The only point being made is that it has very powerful array programming primitives, but those functions can be easily brought to other languages (and indeed a lot of them have those primitives).
Why is it? You're assuming that I know what "mod" means, what the parens and comma signify (and perhaps what the lack of space in mod( but the presense of space after the comma indicate). If I didn't know those thing, they aren't at all readable and there's no way to guess. Wouldn't it be "1 modulo 3" for readability? Look at beginners in various languages posting on the internet asking what the different parens, braces and brackets do and when to use them. And then you're assuming that I don't know %, which because it's so common in C-like languages, I do, but if I didn't the glyph looks like division.
NB. that mod() implies modulus and % is remainder, and "rem" is even worse because it looks like BASIC's "remark" comment word. https://stackoverflow.com/questions/13683563/whats-the-diffe...
It's easier to read "(AA|AB)([0-9A-F]{7,10})ZZ" than to write that regex in a flowchart of if/else branches and string and state manipulation. And easier to verify it's correct. Just because you can write unreadably hideously long regexes doesn't mean regexes should be shunned for unreadability, for a range of patterns they are usable, convenient and powerful.
> "I've never seen the value proposition of these family of languages other than "people who like them say they like them", and by the looks of the comments I don't seem to be the only one."
I'm not sure they have one in the large scale; I would like one as a rectangular-pattern-regex inside another language or shell because of the notation, and not in the sense that "you can do the same thing with numpy". I can write text search in Java, I'd rather use grep.
I have never been able to shake the impression that APL is a troll language, like INTERCAL or brainfuck, except that part of the 'joke' is to insist that there's no joke. APL makes me feel gaslit.
So it has much more in common with math notation as a result, which is why the focus is on expressing yourself tersely with symbols. Also: nobody has to worry about special keyboards with symbols when writing those symbols with chalk on a blackboard, right? So the medium shaped the mode of communication.
I wonder what it would be like to learn programming that way, without using a physical computer. Maybe it would actually be a lot more pleasant for working through programming problems together? Mathematicians seem to be doing just fine working out their problems together on the blackboard with their notation after all.
EDIT: Hah, just saw that elsewhere in the thread an actual mathematician laments the (ab)use of symbols in their field, so I guess I was wrong there. Well, in that case, maybe mathematicians and programmers (or at least language designers) should join forces and see if they can come up with a more ergonomic notation together. A new Bourbaki club, so to speak.
Nope, it should be burned in fire.
> Roughly 86% of all the fun you get from APL programming comes from the mysterious symbols and the magic behind them. It’s not that APL is alien to computers, it’s just the computers were alien to APL for quite a while.
That's being alien to humans my dude. If understanding syntax is heaviest mental exercise in programming language it is unexcusably terrible. It should be considered torture to even require someone to read it.
> "Nope, it should be burned in fire."
With a glance at it, things jump out:
¯1 0 1∘.⊖
¯1 0 1∘.⌽
⊂⍵
that's rotating a matrix by one cell left, same, right: to make three matrices, then shifting those three up and down by one place to make nine with the 'surrounding squares' of each cell. Like so: mat ← 3 3⍴ (0 0 0 0 1 0 0 0 0)
mat
┌→────┐
↓0 0 0│
│0 1 0│
│0 0 0│
└~────┘
¯1 0 1∘.⌽ ⊂mat
┌→────────────────────────┐
│ ┌→────┐ ┌→────┐ ┌→────┐ │
│ ↓0 0 0│ ↓0 0 0│ ↓0 0 0│ │
│ │0 0 1│ │0 1 0│ │1 0 0│ │
│ │0 0 0│ │0 0 0│ │0 0 0│ │
│ └~────┘ └~────┘ └~────┘ │
└∊────────────────────────┘
¯1 0 1∘.⊖ ¯1 0 1∘.⌽ ⊂mat
┌→────────────────────────┐
↓ ┌→────┐ ┌→────┐ ┌→────┐ │
│ ↓0 0 0│ ↓0 0 0│ ↓0 0 0│ │
│ │0 0 0│ │0 0 0│ │0 0 0│ │
│ │0 0 1│ │0 1 0│ │1 0 0│ │
│ └~────┘ └~────┘ └~────┘ │
│ ┌→────┐ ┌→────┐ ┌→────┐ │
│ ↓0 0 0│ ↓0 0 0│ ↓0 0 0│ │
│ │0 0 1│ │0 1 0│ │1 0 0│ │
│ │0 0 0│ │0 0 0│ │0 0 0│ │
│ └~────┘ └~────┘ └~────┘ │
│ ┌→────┐ ┌→────┐ ┌→────┐ │
│ ↓0 0 1│ ↓0 1 0│ ↓1 0 0│ │
│ │0 0 0│ │0 0 0│ │0 0 0│ │
│ │0 0 0│ │0 0 0│ │0 0 0│ │
│ └~────┘ └~────┘ └~────┘ │
└∊────────────────────────┘
How much work is that in Python? Compare with this Python Game of Life found on the internet[1]: https://gist.github.com/amankharwal/e04369de79c4060fb7edab5c... and see that this part overlaps with their line 8, finding the neighbours of a cell: neighbors = [(1,0), (1,-1), (0,-1), (-1,-1), (-1,0), (-1,1), (0,1), (1,1)]
Quick, are their tuples correct or did I sneak in a mistake? Easier to eyeball ¯1 0 1 for correctness, right?The whole APL expression is shorter than their line 14 to copy the board:
copy_board = [[board[row][col] for col in range(cols)] for row in range(rows)]
with its five variable names (easy to mistake col/cols and row/rows), four keywords, chained indexing inside a nested list comprehension. That's Followed by 12 more lines of code dense with 0s, 1s, <, >, >=, ==, row, rows, col, cols, neighbour, neighbours - quick are they all typo-free and all the comparison and boundary cases correct with no off-by-ones?That leaves ∨.∧ as something weird, but it's short so you can try https://aplcart.info see if it's a known idiom or part of one, and if not it won't be much effort to type into a REPL like https://tryapl.org and play with. You can make some boolean arrays to try it in a few characters. What if you don't understand the Python code, how much more work is it to extract it into a test file and make test data and some print functions for it?
> "If understanding syntax is heaviest mental exercise in programming language it is unexcusably terrible. It should be considered torture to even require someone to read it"
The syntax is not the hard part, "how does this data transform solve the game of life" is the hard part, and hiding the data transform in a torrent of fluff like "(r < rows and r >= 0) and (c < cols and c >= 0) and (copy_board[r][c] == 1)" is inexcusably terrible. Details are what computers are good with, and what people are bad with. High level transforms is what people should focus on and tools should enable.
[1] https://thecleverprogrammer.com/2020/12/25/game-of-life-with...
Those symbols look cool. But they're not very far away from Brainfuck.
Or today, custom keyboard mapping.
It's not brevity for brevity's sake - it's understanding the limits of human working memory. The more verbose a description gets, the harder it is to work with it, until at some point, you just can't process it at all (at this point people start making indexes or developing notation to... make things more concise).
Comparing APL with Brainfuck is just ridiculous. The former is designed to be dense to enable efficient work; the latter is a joke that's designed to be sparse.
What ever do you mean? The comparison in the first comment (which I did not write) is apt. They both use a notation of symbols that are derived from Western notation. There was no further comparison with Brainfuck made.
In that comment, APL was further compared with Perl, which perhaps is what you meant to write? Perl's 'write-only' nature largely stems from its ingrained use of regular expressions. There are, indeed, some parallels between regular expressions and APL, both utilizing some kind of notation to concisely describe function.
On that note, regular expressions were the first programming language I ever learned and I feel I have a good handle on them. I still find no joy in reading them. It's simply not a good language to read, even if it can benefit on the write side. I'm not convinced that knowledge and experience makes something more enjoyable. There are a lot of things in life that I have plenty of knowledge and experience in that doesn't translate to enjoyment.
People who decry Perl as a "write-only language" have very rarely given Perl more than a cursory look. It has a lot of syntax, yes. It uses some shorthand symbols, yes, but not to the extent that APL does. The complaints about Perl from C or Python fans are just the same complaints Lisp folks have about C or Python syntax. Most of them are quick to proclaim how superior Python is. Oh, but Perl doesn't have invisible syntax nor a global interpreter lock.
In the rare occasions when I wrote Perl, the language offered all I needed to make my script as boring as Java, along with many temptations to be clever and concise; many people use Perl because it supports write-only "quackery", but it's their choice.
Alcohol can be consumed in moderation, but often isn't.
Parents can raise kids without being emotionally and physically abusive, but often don't.
Marriages can be healthy and stable lifelong commitments, but often aren't.
Education can help raise people out of poverty, but often doesn't.
Governments can provide stability and security for their constituents, but often don't.
Sometimes we all just put up with the unreadable mess when it solves the problem at hand quickly.