5 ms·
I checked it insofar as I understand APL and what the algorithm was attempting to do: that the algorithm was attempting to detect and return the index of the fi
by jcrites 3y ago
I checked it insofar as I understand APL and what the algorithm was attempting to do: that the algorithm was attempting to detect and return the index of the first element of every consecutive "[0 1]" pair.
[Edit: OK, I see the mistake is that it should return the index of the `1`, not the `0`. Yes, that's the kind of mistake I'd catch during unit testing, or after more carefully reviewing the code.]
In what way is its explanation wrong? Its summary of the algorithm is:
> So, this code is finding the indices in the array ⍵ where a 0 is immediately followed by a 1, and replaces these 0s with the first element of ⍵. It then returns the indices of the non-zero elements in the result.
That summary seemed to correctly describe the algorithm, and seemed consistent with the article, so I assumed that its breakdown was correct. I don't understand the individual symbols or operators of APL and can't quickly fact-check the answer, but given that the summary was consistent with the article, it seemed to indicate that GPT had deduced (with no context from the article) what the algorithm was doing in human terms – in other words, whether it was able to "read" the APL code.
Whether it's actually mutating the input or not, I don't know. Its description of the transformation seemed to check out, though.
Regardless of whether its breakdown is right or wrong, my true intended commentary is about the opacity of the syntax and the difficulty in reading it (which I elaborated on via an edit, after your comment was posted but before seeing it).
- rak1507 3y ago<mean message edited out - despite me really wanting to be mean to someone who's been programming for longer than I've been alive but seems to lack reading comprehension> You don't have to understand APL to know what it's attempting. From the article it clearly is meant to return [0,5,9,11,16], your rust returns [4, 8, 10, 15] (at least the second one, the first one doesn't even compile!).
- jcrites 3y ago> From the article it clearly is meant to return [0,5,9,11,16], your rust returns [4, 8, 10, 15]. You're right, I didn't test the code, nor review it especially closely. I took a quick glance for a couple of seconds, checked that it compiled, glanced at the primitives it was using, and said "LGTM". I wanted to know "What general shape will this algorithm take expressed a different way?" You shouldn't expect perfection from someone of any skill level posting or discussing topics casually like this. The amount of time and effort I'm willing to spend on comments is limited – limited enough to allow an off-by-one error to slip through. This is commentary in an Internet forum, not a code review for a production system, or a formal publication. However, I think the nature of the error and its fix actually reinforces my point. If one did review the Rust code closely (which I didn't – I was more interested in GPT's capability to explain the APL syntax; and what the algorithm would look like expressed in another language), then a mistake would have stood out: .filter_map(move |(i, window)| { if window == &[0, 1] { Some(i) If we want to return the index of the `1`, not the `0`, then `i` is the wrong index to return. I assume that's the mistake you're pointing out. Yes, it's true that I didn't even realize that the original algorithm was returning the second index of these elements and not the first. I barely skimmed those details before becoming entirely distracted by APL's syntax itself, and then started to wonder about the various other ways that such an algorithm might be implemented in another language (and how clearly, subjectively). "The APL code is opaque. Will alternatives be opaque?" Yes, a mistake like this would be trivially caught upon a close review of the algorithm or code, or on any unit testing. However, I think it bolsters my point that the correction to the Rust code is easy to understand – both the mistake and the nature of the fix: .filter_map(move |(i, window)| { if window == &[0, 1] { Some(i + 1) (The only thing that's not immediately obvious is why `i+1` is guaranteed to be a valid index – which it is.) [Edit: Now that I've had time to actually run and test the code, a second error is that it omits the first group of `1`s. A corrected version is: fn find_zero_one_indices<I>(input: I) -> Vec<usize> where I: IntoIterator<Item = i32>, { let input: Vec<_> = std::iter::once(0).chain(input.into_iter()).collect(); input.windows(2) .enumerate() .filter_map(|(i, window)| { if window == &[0, 1] { Some(i) } else { None } }) .collect() } This returns `Some(i)` again rather than `Some(i+1)` because we've prepended a `0` to the input.] My comment is not about Rust specifically. It's just the language I chose. I assume the translation would be roughly similar in Java (with iterators), Python, Ruby, and the imperative version in C and C++ and similar. And I believe in most of these languages, the mistake and its correction would both be easy to see and understand with close enough review. I'm not certain that would be true for the APL code. If you gave me that algorithm in any mainstream language, and asked me to look for mistakes, I could probably spot that problem upon reviewing it, and probably know how to fix it. (Probably, not necessarily.) I do not believe that I could spot an analogous problem in the APL code nor understand easily how to fix it. My overall point is that the APL code seems entirely unapproachable to the un-initiated – even for a programmer experienced with numerous other languages. (I might have similar difficulty with Haskell, but probably not as much; and perhaps Scala if it was written in a particularly obscure way.) ---- An additional topic that I would be interested to explore is: what kind of errors would be likely in the APL code? What would the APL code look like that had a similar off-by-one error? Would it be easy to spot by reading the code? And what would the "diff" look like correcting it? I unfortunately don't know enough about APL to explore this. ---- [In response to several edits of your comment that contained ad hominem attacks, and a lack of explanation of your criticism:] Please follow the Hacker News guidelines: https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html > Be kind. Don't be snarky. Converse curiously; don't cross-examine. Edit out swipes. > Comments should get more thoughtful and substantive, not less, as a topic gets more divisive. > When disagreeing, please reply to the argument instead of calling names. "That is idiotic; 1 + 1 is 2, not 3" can be shortened to "1 + 1 is 2, not 3."
- rak1507 3y ago[flagged]
- dang 3y agoI'm afraid your comments are unfortunately still well on the wrong side of the HN guidelines. In your GP comment, "someone who's been programming for longer than I've been alive but seems to lack reading comprehension" is a swipe, and the comment I'm replying to here is way too aggressive. "I expect you to test" is supercilious, "complete nonsense" is name-calling, "I don't believe you could fix it in APL [...] but then again you can't seem to fix it in any other language either" is a personal putdown, as is "Clearly rust is too as you posted rust code that doesn't work". I happen personally to agree with you about shallow dismissals of APL and the other array languages and have felt rather strongly about it at times as well, so I completely get where you're coming from. But that makes it painful for someone like me to read nasty posts flaming people for getting it wrong (or what you and I would call wrong). All that achieves is to alienate not only the person you're talking to but also any neutral readers who don't know much about the subject—and that is the vast majority of readers. It not only doesn't help your (our) position, it gives people a new reason to have negative associations with these little-understood languages, which are much too beautiful and powerful to deserve that. You clearly know a lot about this topic and you're more than welcome to share what you know on HN. One function of this site is to be an educational hub for non-mainstream knowledge about computing (and other topics as well, but especially computing). However, we need you to do so within the site guidelines (https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html) which includes being respectful and kind to people who know less than you. It's great that you edited out the worst personal attack and the fact that you did that makes it clear that you have good intentions—which I appreciate. But it isn't enough to leave posts that are full of putdowns. We really can't bend these rules, nor is it in your interest for us to bend them because, as I said, all they do is make your minority position even more of a minority position, and that hurts you yourself as well as the rest of us who love these languages. I definitely hope you'll keep posting and sharing interesting things about APL, but if you'd please review https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html and take the intended spirit of the site more to heart, we'd be grateful.
- jodrellblank 3y ago> can't quickly fact-check the answer If you would like to, visit https://tryapl.org/ https://tryapl.org/ and enter: ⎕IO ← 0 bools ← 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 0 1 1 1 1 {⍸(⊃⍵)@0⊣¯1⌽0 1⍷⍵} bools The website will only(I think) let you copy-paste line by line, or it has the symbols in a bar along the top you can click on to enter them, and it has a backtick prefix system for typing them, so `L will enter the quad square on the first line and `[ enters the left arrow. Left arrow is variable assignment and the variable with a quad is a system one. The top line sets array indices count from zero instead of the default indexing from one. The curly braces {} make the code into a scriptblock/anonymous function which is immediately executed on the argument "bools". If you want to see it building up stage by stage it works from the right, these give the intermediate steps: {0 1⍷⍵} bools {¯1⌽0 1⍷⍵} bools {(⊃⍵)@0⊣¯1⌽0 1⍷⍵} bools {⍸(⊃⍵)@0⊣¯1⌽0 1⍷⍵} bools > "Regardless of whether its breakdown is right or wrong, my true intended commentary is about the opacity of the syntax and the difficulty in reading it (which I elaborated on via an edit, after your comment was posted but before seeing it)." Which is a bit of a shame because the point of the article is at the end: "I do not believe that you can leverage this kind of suggestivity with languages that are more verbose. [...] It is fundamentally easier to try out many single line expressions than it is to try out many 15 - 30 line expressions. [...] in the same way that any technique that reduces the length of the feedback cycle improves our ability to iterate and therefore learn.". It's not saying that APL is easy to read, it's claiming that learning to read it/think in it has benefits that don't apply to longer languages - more forest less trees, more design less bricklaying. Taking that away into "I never learned it and it looks hard" is not going with the more interesting part of the claim - like, would you rewrite your Rust code to detect the end of groups, then compare both versions and see they are annoyingly clunky, then search for a version which is more pleasing and suggests variations which may do other useful or interesting things with the groups? Even if you did, doing so may be harder because the Rust code is so much longer (more effort to compare in your head) and you would be less able to because the Rust code took more time to write so you have less time left over. [This is rather more for the world of doing a mathematical puzzle, seeing two equations look similar and realising that the puzzles share some common underlying thing which you hadn't noticed before, than the world of writing production webservers with fearless concurrency].