Ivy – An interpreter for an APL-like language
pkg.go.dev
pkg.go.dev
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] def primes (array.skip(count.@, 1)..
tuple(@, {mul.@:combo(@,@)})..
tuple(T=second.@, ?[1!=has(T,@),@:first.@])),
primes.3000
https://tab-lang.xyzI 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?
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
I see that requesting https://robpike.io/ivy@latest yields a 302 that points to http://godoc.org/robpike.io/ivy@latest (not sure exactly what go install would do with that URL though)
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 so… whatever is happening here might not be on purpose, actually.
<meta name="go-import" content="import-prefix vcs repo-root">
The code can reside anywhere, independent from the domain in the import path.https://pkg.go.dev/cmd/go#hdr-Remote_import_paths
Edit: I see in another comment that you tried to curl https://robpike.io/ivy and got a 302 redirect to pkg.go.dev. That's meant for humans. You need to add ?go-get=1 for the go toolchain:
$ curl 'https://robpike.io/ivy?go-get=1'
<meta name="go-import" content="robpike.io/cmd/doc git https://github.com/robpike/doc.git"> ...
Personally I don't bother with responding differently based on the go-get query param. I just put a <meta http-equiv="refresh"> alongside the <meta name="go-import"> so that the whole thing can be served statically and still be useful to both humans and machines.Even works with curl :-)
curl --no-buffer https://robpike.io> 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.)
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.
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
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)
((2*a) + (2*b)) / c
in math would be 2a + 2b
-------
c
Traditional precedence rules make more sense with traditional handwritten notation.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.
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
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.
WUFFS doesn't have operator precedence. 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.
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.
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.
A flagrant example of
> idiosyncratic, not that user friendly, and mostly "works for me" affair
being date/time patterns in Go.
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.
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".
What's the point in creating something new if you simply repeat what already exists?
Refactoring?
Making a FOSS version?
Learning?
Doing it in Rust because it's fashionable?
Competition with an existing player in the same market?
And lots of other reasons besides...
Now, you might disagree with that, but at least disagree with what I tried to say, not what I didn't mean :)
For method capitalization, I'd say no, as this is the case in any other popular languages too (C# to name but one).
Not completely unique (e.g. variables v symbols in erlang, concrete type v generic placeholder in haskell) but really rare, and usually the capitalisation isn’t a switchable thing, it’s a very fixed meaning.
This approach to precedence comes straight from Iverson and APL itself. Iverson originally started out designing a more uniform mathematical notation. It developed into a programming language secondary to that. Note that J, K, and others in this family all duplicate this choice largely. And there's mainstream languages that have chosen the middle ground of allowing basic precedence for + - * / expressions but require explicit grouping otherwise.
It's not a particularly outlandish idea.
So attributing it to Rob Pike's personality traits is just off the mark. It's ok to be critical but it should be specific and informed, not just bashing someone character as a whole, and if you're gonna take it that far, you'd probably better at least know what you're actually talking about.
And note I've been critical of Rob's choices and behavior surrounding Go's date/time on a particular issue, so note this isn't empty hero worship on my part.
That's fine, since I didn't speak about Pike's "personality traits", but to his architecure/design tendencies.
And I didn't attribute this design to him. I know of APL, and even if I didn't the influence is right there in the TFA title. I compared it to his designs ("sounds like a typical Rob Pike design"), i.e. he adopted it because he does have these design tendencies, and so this was to his taste.
>not just bashing someone character as a whole
Where exactly are you getting that from? As if I've called him a "bad person" or something?
It's actually from APL.
Not about character in general, much less about "rubbishing" it.
In light of this, "sounds like you have something personal against Rob Pike", is moot.
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.> 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.
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.
It's more like going to Japan to ride a Japanese train. Would you rather build a full-scale replication in your back yard?
APL / Ivy have so many operators a conventional precedence order would likely be completely impossible to remember or work with.
(One option I’d consider viable in general would be to define associativity and perhaps compatible groups like {+, -} or {*, /} but force explicit parentheses when operators from different groups are used, but that wouldn’t feel like a calculator.)
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.
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_preceden...
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
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
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. :)
https://aplwiki.com/wiki/Array_model
And it sounds like you've found it, but Nial does have the RANK transformer, which looks essentially the same as J's rank conjunction " .
I think if you tried APL for a bit, you'd quickly get over the symbols (and even come to prefer them eventually).
This seems like a blatant unforced error.
(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.)
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.
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...