Hacker News new | ask | show | jobs
by drbaba 894 days ago
Based on e.g. [this classic](https://youtu.be/a9xAKttWgP4?si=oMQQVbIziq60Cd1F), it seems people are fluent and productive in APL in a way I doubt anyone can become in Brainfuck.

But I would also like to know from APL aficionados whether it is a “write-only” power tool akin to a “Perl for math”, or if it’s also easy to read other people’s APL code once you get used to the most common symbols in APL.

1 comments

I don't put a lot of stock in the "write-only" accusation. I think it's mostly used by those who don't know APL because, first, it's clever, and second, they can't read the code. If I remember I implemented something in J 10 years ago, I will definitely dig out the code because that's the fastest way by far for me to re-learn how it works.

This project specifically looks to be done in a flat array style similar to Co-dfns[0]. It's not a very common way to use APL. However, I've maintained an array-based compiler [1] for several years, and don't find that reading is a particular difficulty. Debugging is significantly easier than a scalar compiler, because the computation works on arrays drawn from the entire source code, and it's easy to inspect these and figure out what doesn't match expectations. I wrote most of [2] using a more traditional compiler architecture and it's easier to write and extend but feels about the same for reading and small tweaks. See also my review [3] of the denser compiler and Co-dfns.

As for being read by others, short snippets are definitely fine. Taking some from the last week or so in the APL Farm, {⍵÷⍨+/|-/¯9 ¯11+.○?2⍵2⍴0} and {(⍸⍣¯1+\⎕IO,⍺)⊂[⎕IO]⍵} seemed to be easily understood. Forum links at [4]; the APL Orchard is viewable without signup and tends to have a lot of code discussion. There are APL codebases with many programmers, but they tend to be very verbose with long names. Something like the YAML parser here with no comments and single-letter names would be hard to get into. I can recognize, say, that c⌿¨⍨←(∨⍀∧∨⍀U⊖)∘(~⊢∊LF⍪WS⍨)¨c trims leading and trailing whitespace from each string in a few seconds, but in other places there are a lot of magic numbers so I get the "what" but not the "why". Eh, as I look over it things are starting to make sense, could probably get through this in an hour or so. But a lot of APLers don't have experience with the patterns used here.

[0] https://github.com/Co-dfns/Co-dfns

[1] https://github.com/mlochbaum/BQN/blob/master/src/c.bqn

[2] https://github.com/mlochbaum/Singeli/blob/master/singeli.bqn

[3] https://mlochbaum.github.io/BQN/implementation/codfns.html

[4] https://aplwiki.com/wiki/Chat_rooms_and_forums

Yeah, about fifteen minutes for lines 15 to 21. Which includes getting used to this n-(⊂¯1++⍀m)⌷(m←c=LF)⌿n←+⍀ pattern for sum-within-lines that appears everywhere. Pretty sure the k=¯1 checks do nothing (planning ahead for a future feature?) and I think it breaks if there's a quote character in a comment. But, like... line 19 sets k to ¯2 where there are whitespace characters that come before any non-whitespace character on the line other than - ? or : followed by whitespace? I don't know YAML well and I have no idea how this fits in. So it's hard to remember what ¯2 means as I read later code.
You absolutely rock. Thanks for taking a look at my project. It's currently on the back-burner right now, but I do have future plans. The ¯2 is specifically something I'm hoping to get rid of. It has to do with some specifics of handling leading sigils, but it's slightly broken and the ugliness of ¯2 signals to me that it needs to be fixed.

Hoping to hear your thoughts in the future once the project is more in shape!

In the BQN compiler I'd write (⊂¯1++⍀m)⌷(m←c=LF)⌿ as the equivalent of (⊂⌈⍀m×⍳≢m←c=LF)⌷ using the function IT (indices-times but it also includes the ⌈⍀). Although I'm not sure it's inherently faster. Most of the cost is in selection, and there's an algorithm taking a shuffle of a sliding window from the right argument that would work better with the denser indices. And those indices have a smaller type which may be useful. The annoying thing is that this whole set-and-hold operation could be implemented in SIMD directly and none of those complications would apply. But it's pretty hard to expose in a nice way without just providing a builtin.