8 ms·
Ivy – An interpreter for an APL-like language
- kevingadd 4y agoThe precedence rules are terrifying. I get it, but: > 3/6*4 is 2 while 3 / 6*4 is 1/8 since the spacing turns the / into a division operator. Use parentheses or spaces to disambiguate: 3/(6*4) or 3 /6*4. having to be up-front as a warning feels like a sign that your approach to precedence is fundamentally broken and you should require parentheses. (Also the idea that 1/8 and 1 / 8 are different things feels bonkers to me in general, but maybe that's just taste.)
- legulere 4y agoI wonder if programming languages having precedence rules at all is an atavism from the 70s when it was an interesting problem for parsing. Adding parentheses makes things clearer in 99% of the cases.
- tgv 4y agoIf memory serves well, normal operator precedence was already present in the first FORTRAN, which was proposed in 1953. And APL's priority system is: there is no priority. Everything is evaluated right to left. Pike's Ivy is no exception. 3/4 differing from 3 / 4 is a lexical convention: 3/4 is a rational number.
- bruce343434 4y ago> Adding parentheses makes things clearer in 99% of the cases I will challenge that in saying that 9*2+3/2^3 is clearer than the far more noisy (9*2)+(3/(2^3)) Precedence is something you learn in high school. edit: fighting with the painful markdown of hn
- pasc1878 4y agoIt is not that easy see the many threads over BODMAS/PEDMAS/BEDMAS. If you actually do maths you never have the / or ÷ operator in writing equations it is always a horizontal line so you can't write maths in one line. In your case I think the bracketed form is easier to read If forced to write on one line suspect I would write as 9*2 + 3/(2^3)
- nerdponx 4y agoAnd multiplication is very often written as two variables just sitting next to each other with no additional operator character in between. ((2*a) + (2*b)) / c in math would be 2a + 2b ------- c Traditional precedence rules make more sense with traditional handwritten notation.
- laumars 4y agoI think all the points there are true: The latter example is more noisy, you do learn precedence in high school yet the latter example is also more clear because it is the most accurate way of conveying intent.
- nerdponx 4y agoThis is the 1% of cases!
- pasc1878 4y agoNo it predates that. I think in an attempt to use the way arithmetic is usually written. See https://rosettacode.org/wiki/Operator_precedence https://rosettacode.org/wiki/Operator_precedence for a list. COBOL, FORTRAN and Algol60 all have that so this dates from the '50s I think out of major languages only LISPs, APL and successors and Forth don't have precedence rules
- somat 4y agoPrograming languages require precedence rules because mathematicians decided that having a screwball precedence would make their notation more concise, over the hundreds of years of being used and taught these notations have become the expected form of math, and programing languages(all of which tend to be math heavy) usually will try to follow the expected rules. Honestly as an interested amateur I think that much of the notation used in math is one of the weakest parts of the discipline. there are two things that I think would aid the notation greatly. 1. Most complex equations have a lot of moving parts within them, however the notation has no way of indicating what these parts are for and why they are there, you better hope that the author has taken to time to document their equation properly. 2. the terrible symbology. you have heard the joke about the two hard things in computer science. it turns out that programmers are usually fairly good at naming things, the mathematicians are the true dark masters at names. if you have an item in your equation that represents the confidence of a rating they will not name it confidence_rating, no, they will name it σ(a small sigma), good luck searching(or even typing) that. Now I get why it was done, they tended to a notation that was as concise as possible, this makes it much faster to manipulate parts when you are working on something. however I feel this has the opposite effect when trying to teach it to others.
- rob74 4y agoWell yeah, having precedence rules makes the notation more concise and can save you from typing lots and lots of brackets. And I don't think multiplication/division having higher precedence than addition/subtraction (and, by extension, AND having higher precedence than OR) is all that "screwball" - and even if it were, if you paid attention in elementary school, you already know it, so programming languages can rely on it. Of course, the moment they start getting "creative" with precedence, those exceptions turn into massive footguns...
- tialaramex 4y ago> Programing languages require precedence rules WUFFS doesn't have operator precedence. https://github.com/google/wuffs/blob/main/doc/wuffs-the-language.md#operators https://github.com/google/wuffs/blob/main/doc/wuffs-the-lang... As its designers explain: A bare a * b + c is an invalid expression. You must explicitly write either (a * b) + c or a * (b + c). Why doesn't WUFFS have precedence? Because it's focused intensely on solving its specific problem, Wrangling Untrusted File Formats Safely. Having solved the buffer problem (you can't write buffer[oops_too_big] type mistakes in WUFFS, they will not compile) and the integer overflow problem (likewise, it doesn't compile) they wanted to also solve that problem where the programmer thought there were making one calculation, but due to precedence rules they were actually making a different calculation.
- masklinn 4y ago> I wonder if programming languages having precedence rules at all is an atavism from the 70s It's not an "atavism from the 70s", it's a mirror of mathematical conventions, as well as a syntactic convenience. Language designers have tried to do away with precedence all along by having uniform evaluation (e.g. smalltalk, as well as APL and all its descendents hence Ivy, probably), removing infixes (lisp, forth, assemblies), or requiring explicit prioritisation (I think I saw that a while back though I don't remember the language). > Adding parentheses makes things clearer in 99% of the cases. It also adds a significant amount of noise for 99% of the cases, for no value since any schoolchild past 12 or so has integrated the precedence rules.
- Macha 4y ago> It also adds a significant amount of noise for 99% of the cases, for no value since any schoolchild past 12 or so has integrated the precedence rules. As all the viral "Only 25% of people got this right" stuff that pops up from time to time proves: No they haven't. Also since we're rarely writing equations composed entirely of single digit numeric literals and are using reasonable variable names, the percentage of characters overhead and therefore noisiness of using brackets is much less than in the short examples being thrown around.
- coldtea 4y agoSound like a typical Rob Pike design. Idiosyncratic, not that user friendly, and mostly "works for me" affair (considering things like the Sam editor and parts of Golang).
- Jabbles 4y agoGiven that Go does not have the same syntax, you cannot claim that these are examples of "typical Rob Pike design".
- masklinn 4y agoGP's not talking about this specific syntax but about Rob Pike's general approach to language and system design. A flagrant example of > idiosyncratic, not that user friendly, and mostly "works for me" affair being date/time patterns in Go.
- Jabbles 4y agoYou can't just cherrypick examples and say this is typical. Even worse, you (GP) can't say this is typical without providing any examples when the most obviously relevant analogy (precendence in Go) does not support your statement.
- eis 4y agoYou are misunderstanding his point even though masklinn explained it. It's not about the specific point of operator precedence. It is about designing something that has internally sound logic but is very unexpected by a typical new user. And he provided the example of time package patterns in Go which imho fits very well. Yea it makes sense but I'm sure there are hordes of users that think "why doesn't this work like in virtually every other language?". It's probably good to not take the "typical" too literally and more as a "Rob Pike has done a few designs in the past that have this quality".
- mseepgood 4y ago
- dan-robertson 4y agoIs it just that fractions are first-class objects? And I guess then you just want to always separate operators with spaces.
- masklinn 4y ago> Is it just that fractions are first-class objects? The problem is that 3/4 is a rational literal, while 3 / 4 is a division. This seems unique(ly error prone) in the language, other operators do not have to be spaced.
- kqr 4y agoThis is odd particularly as : the traditional ratio symbol seems free.
- eis 4y agoFully agreed. I stopped considering this practical in any way when I read > 3*4+5 is 27 I'm sorry but if your calculator does not follow standard mathematical rules for operator precedence then I'm out. But the space issue takes it to another level. I also get it, it derives from APL which is right to left and all operators have same precedence but it's just so far from practically usable for normal people... there's a reason noone uses APL today. And sure it's just a plaything but seems weird to even create apps for iPhone, iPad and Android and a logo for it.
- iasay 4y agoAgree with this. I’d rather actually we used postfix notation as that not ambiguous at all. I would like a modern “dc” written in Go if I’m honest. With engineering units, BCD decimal arithmetic, blackjack and hookers. Actually if there was a postfix notation spreadsheet with that capability it would be an interesting tool.
- is0tope 4y agoOne thing I really like about kdb+/q is the fact that it has strict right-to-left execution/precedence. While I know it's a standard, I don't want to deal with bodmas, or whatever it is. Having right to left makes it clear and unambiguous how it will execute. Saying that, it does also encourage huge one line abominations. Everything in moderation i guess...
- vonwoodson 4y agoI keep a YouTube video in my back pocket just for this argument: [The Order of Operations is Wrong by mintuephysics](https://youtu.be/y9h1oqv21Vs https://youtu.be/y9h1oqv21Vs)
- jasonwatkinspdx 4y agoYeah, there's a legendary twitter thread that removed all doubt for me. Thousands of teachers, professors, and engineers all confidently asserting that their version of PEDMAS is the correct and unambiguous one. Stuff like this is very difficult to change, because the conventions both global and fundamental... but we also shouldn't pretend like history happens to always chose the perfect convention. It's more a matter of we've just learned to live with the warts.
- hhyndman 4y agoAPL was the first language I learned in school and I was thrown by the precedence of the mathematical operators, but once the other operators were put in play, it was an incredibly simple rule -- and rarely did I or other APL developers have bugs relating to order of operation. I then moved to C++ and was gobsmacked the the precedence rules and was forced to use parentheses to get things right. I have seen hundreds of bugs produced by programmers that tried to be clever and avoid parens relying on their faulty memory of the precedence priorities. Just look at the C++ Operator Precedence table listed at the following URL. It's wild! https://en.cppreference.com/w/cpp/language/operator_precedence https://en.cppreference.com/w/cpp/language/operator_preceden...
- hhyndman 4y agoAn interesting article relating to "operator precedence is broken". https://www.foonathan.net/2017/07/operator-precedence/ https://www.foonathan.net/2017/07/operator-precedence/
- frankjr 4y agoFor those curious to see the language in action, Russ Cox recorded solutions to many of the AoC 2021 challenges in Ivy. https://www.youtube.com/user/rscgolang/videos https://www.youtube.com/user/rscgolang/videos
- Saser 4y agoRuss Cox (who worked together with Rob Pike on Go for a long time) solved several of last year's Advent of Code puzzles using Ivy. Here's a YouTube playlist where he has recorded himself doing so: https://youtube.com/playlist?list=PLrwpzH1_9ufMLOB6BAdzO08Qx-9jHGfGg https://youtube.com/playlist?list=PLrwpzH1_9ufMLOB6BAdzO08Qx.... I don't think he's solving the problems for the first time in these videos, instead merely demonstrating how they can be solved using Ivy.
- cpach 4y agoOut of curiosity: I noticed that Pike chose the, uh, “username”, robpike.io for this project. (It’s probably called something else than username in this context.) What are the benefits of using a domain name as username/organization name in this context?
- unsafecast 4y agoYou're not dependent on GitHub. If you ever decide to switch to, say, sourcehut, you can keep the install command and not break anything. It also looks way nicer, and it's easier to deal with (I'd rather type `import ”robpike.io/ivy”` than a GitHub link), but that's a flaw in the way go does packages imo
- cpach 4y agoAh. Interesting. I see that requesting https://robpike.io/ivy@latest https://robpike.io/ivy@latest yields a 302 that points to http://godoc.org/robpike.io/ivy@latest http://godoc.org/robpike.io/ivy@latest (not sure exactly what go install would do with that URL though)
- p4bl0 4y agoMaybe it doesn't do this redirect if the user agent is the one of go install? It would be a convenient way to have the package url works for both the package itself and its documentation :). EDIT: well now for me it redirects to: https://github.com/golang/go/issues/43036 https://github.com/golang/go/issues/43036 so… whatever is happening here might not be on purpose, actually.
- unsafecast 4y agoAs far as I know, ‘go get’ (not install; that's different) uses git to download a repository.
- unsafecast 4y agoOh, sorry. It's install after all. I assumed it's a library.
- titzer 4y ago> Unlike in most other languages, operators always have the same precedence and expressions are evaluated in right-associative order. That is, unary operators apply to everything to the right, and binary operators apply to the operand immediately to the left and to everything to the right. Thus, 34+5 is 27 (it groups as 3(4+5)) This seems like a blatant unforced error.
- mananaysiempre 4y agoThis is entirely in line with the APL tradition. I suspect part of the motivation is that APL has a lot of binary operators, none of which have a conventional infix form in traditional mathematics or anywhere else. (Cf also the Smalltalk tradition, which associates all “binary messages” to the left, but that has the motivation of allowing user-defined names without fixity declarations.)
- anonymous_sorry 4y agoIvy is described as a "plaything". Rethinking rules that everyone takes for granted and seeing where it leads seems like a fun way to play. My first CASIO scientific calculator at school didn't understand operator precedence. Since that was how basic calculators worked too, it seemed perfectly natural. I loved that calculator - there was a simplicity and purity to it. When I got a fancier one at uni that had been taught BIDMAS, it took me a long while to get used to, and I never really enjoyed using it. I don't think it was just because the squidgier keys were less satisfying to tap.
- cardanome 4y agoNow, let's imagine an APL-like language with precedence: APL has a huge number of operators and worse, you can and will define your own, as the classic distinction between operators and functions does not apply to APL. So a huge precedence table to memorize! Plus, with user defined operators you would either have to force them to be all the same precedence, which is kind of a bummer, or you allow them to define their own precedence. It should be obvious that this would be a huge mess. So actually no having precedence is the most sane way forward but you also gain something: Order of precedence errors are quite common both in mathematics and programming. Doing away with precedence rules gets rid of a whole class of errors. Awesome! (If you are going to respond that you never make any errors, well congrats on being smart, I am not. I try to avoid relying on lesser known precedence rules in my code as best as I can.) So what do we gain from precedence rules again? Shorter and less noisy? Ugh, have you seen APL? I think they are good. The notation of APL is explicitly designed to be human friendly. Lot's of thought was put into it. I recommend reading this Iverson paper: http://www.sigapl.org/Articles/Notation%20as%20a%20Tool%20of%20Thought_a1979-iverson.pdf http://www.sigapl.org/Articles/Notation%20as%20a%20Tool%20of...
- henrydark 4y agoIt took me a while to understand the syntax in general and the primes example in particular. For those facing the same obstacle, here is what I understood: 1. Read single lines from right to left. 2. Imagine a stack of one variable that you keep replacing the top as you go from right to left, kind of like concatenative languages (e.g. FORTH, kitten, factor), but right to left instead of left to right. 3. Here is a step by step translation of the primes example to imepartive pseudo code: op primes N = (not T in T o.\* T) sel T = 1 drop iota N First of all this is a function definition, so can be put to function primes(N) return (not T in T o.\* T) sel T = 1 drop iota N Now we apply the two rules above: function primes(N) x = iota(N) // 1..N x = drop(1, x) // 2..N T = x ToT = outerproduct(T, T) // a*b for all a, b in T, so 4,6,...,N^2 return [x in T not in Tot] So we get a O(N^2) (or maybe O(N^3), depending on how `in` is implemented) algorithm for primes until N. Here is a similar algorithm in python that might help further: def primes(N): T = range(2, N) ToT = [a*b for a in T for b in T] return [x for x in T if x not in ToT]
- deleted 4y ago[deleted]
- otabdeveloper4 4y agodef primes (array.skip(count.@, 1).. tuple(@, {mul.@:combo(@,@)}).. tuple(T=second.@, ?[1!=has(T,@),@:first.@])), primes.3000 https://tab-lang.xyz https://tab-lang.xyz
- dan-robertson 4y agoI guess you’ve added a backslash in the outer product to prevent HN formatting weirdness. It isn’t an outer product where the operation is ‘scan product’.
- ianthehenry 4y agoI really like Ivy as a simple, friendly introduction to APL. There is a surprising lack of APL-derived languages that use words to name things -- most stick with the original symbols; J and friends choose equally-cryptic symbols composed of ASCII characters. Earlier this year I decided to solve AoC 2021 in Ivy, then watch Russ Cox's videos to see how he did it and use that to learn something about array programming -- a topic I knew absolutely nothing about going into this. Unfortunately, Ivy really is, as Rob Pike says, a plaything. It is buggy -- if you ever write a function that returns a vector or a higher-rank array, you are entering bizarre undefined behavior territory. The array-language equivalent of "concat_map" or "flat_map" or "mapcat" or whatever you want to call it just produces garbage values, which is very confusing when you're learning about array programming for the first time ("Wait, this vector says its length is 25, but it contains 50 elements...?" or "The transpose of this array is just the first column repeated over and over??"). Beyond that, a very cool thing about array languages is that, you know, functions can implicitly act on entire arrays. You can multiple a vector by 2 and it will know to multiply every element in the vector by 2, because multiplication is defined for scalars. But in Ivy, this is only true for the built-in functions. There is no way to write user-defined functions that have this implicit act-on-every-element behavior. Which is basically the looping primitive in array languages -- so to do anything nontrivial, you have to write it out with explicit recursion (still with the caveat that your functions can only return scalars, or you enter undefined behavior town) or rewrite your operations as binary operations with an ignored right-hand side and use "fold" to "map" them. It's bad. The latter is crippling enough that Russ Cox eventually forks Ivy to add support for it, but it is not currently part of the language. https://github.com/robpike/ivy/pull/83 https://github.com/robpike/ivy/pull/83 Anyway that's a long comment to say: Ivy is a good, friendly introduction to APL syntax (stranding, ambivalent functions, precedence, etc) and some array language concepts, but it is far more of a calculator than a programming language. But it's a good arbitrary-precision calculator! And if you're still interested in trying it, maybe check out this thing I made. It's an... Ivy programming environment?... that lets you run Ivy scripts and see the results inline. (Ivy's repl is... very primitive, and has to be wrapped by something like readline. Russ Cox uses 9term to get around this; self-modifying programs are my preferred approach.) https://github.com/ianthehenry/privy https://github.com/ianthehenry/privy My frustration with Ivy led me to look into other array languages, trying to find one that 1) used English words instead of cryptic symbols and 2) worked. And I really couldn't find any! Someone should do something about that. :)
- meltedcapacitor 4y agoCan't have an APL family post without mentioning Klong! http://t3x.org/klong/ http://t3x.org/klong/