This is actually pretty neat. But I'm having a hard time understanding how to ergonomically write with glyphs. What's the intended workflow. Remembering a bunch of shortcuts to get ⌕ instead of just typing `find` seems harder to read and write.
Edit: I think I understand from the language tour. You're supposed to write the ascii names like `find` then running the program converts built-ins to glyphs.
It's basically "the auto-formatter takes care of it, and integrated highlighting makes it easy to remember what each glyph does until it's memorized". Imagine if gofmt or prettier actually replaced built-in function names.
Also, the editor in the language has an expandable dedicated glyph panel (click the "Show Glyphs" or "Hide Glyphs" button on the upper right; on the front page it is expanded by default in the top example and the Pad editor page but then hidden on the rest of the embeds).
That glyph panel is pretty neat because it also serves as a language reference and you can ctrl+click into the documentation pages.
I had no experience with array languages and decided to give it a try.
It took me 4 hours to write FizzBuzz using only Uiua docs for help:
# create an array of number 1-100
ns ← ∵(+1)⇡[100]
# make a copy of it in a string form "1"-"100"
nsStr ← ∵(□$"_") ns
# every i % 3 == 0 is replaced with "Fizz", everything else is ""
f ← ∵(□▽∶ "Fizz" =0◿3) ns
# every i % 5 == 0 is replaced with "Buzz", everything else is ""
b ← ∵(□▽∶ "Buzz" =0◿5) ns
# every i % 3 == 0 && i % 5 == 0 is replaced with "FizzBuzz", everything else is ""
fb ← ∵(□▽∶ "FizzBuzz" × =0◿5∶ =0◿3 .) ns
# combine them into a 2D array
gs ← [nsStr f b fb]
# run a columnwise map
# | pick the greatest string of each column
# | |
⍉ ≡ (⊡⊢⇌⌂.) ⍉gs
Inability to use maximum function with arrays of different sizes is a bummer, I had to workaround it with grade and pick.
That's a good start! I'm not exactly great with array langauges myself, but I think it's simpler to fill an array with □"Fizz", one with □"Buzz", one with □"FizzBuzz", then create another indexing array and use pick:
Neat solution! Yes, I'm aware of `/↥`, but it finds maximum within a single array of values of the same shape. But what if I have two values of the same shape? E.g. `↥[][1]` throws an error. So I have to either `fill` them to the same shape or use `grade`.
I want to suggest an alternative encoding/notation where instead of single (very nicely chosen) Unicode codepoints, the operators are single (perhaps less well-suited) printable ASCII characters. This would make the language into its own, human-authorable, bytecode!
Visually would look kind of like K, yes; but K (obviously) isn't a stack language, and more importantly, K has operators that consist of multiple characters, and circumfix operators like {}, etc. So it really has none of the qualities that a bytecode has. Whereas Uiua/ASCII would have all of the qualities that a bytecode has.
It looks unlike anything I've ever seen before. Are there any other languages that use glyphs so heavily? What was your inspiration? I have no idea how I would use this language, but it's put a smile on my face. Amazing work.
I hate right to left. In my mind functions act from the right. They are even denoted with a little arrow pointing left to right. Thank god OOP methods, UFCS and streams/pipes and nearly everything goes from left to right, top to down. (AFAIK not long ago some algebraists tried to do algebra, linear algebra and category theory left to right, so f:A->B and g:B->C would compose to fg/fog/f.g.. :A->C. But probably they do it less nowadays, the attempt failed, and math remains right to left.)
I'm a big fan of stack-based languages conceptually, but they always seem to fall flat when it comes to basic reading comprehension. APL has the same issue, as does J. Factor did improve on this a little bit by eschewing the symbol fetish but it was still very difficult to rapidly scan the code for functionality. I'm not convinced the approach shown here is a good pairing with the human brain.
If (and I grant, this is a big if) you are used to them, the symbolic nature of APLs allows to discuss code fragments (and even entire* algorithms) using inline elements instead of as separate interspersed blocks.
The difference between scanning algol-style and apl-style code is a little like the difference between scanning history books and maths books: on one hand, one must scan the latter much more slowly (symbol by symbol, not phrase by phrase), but on the other hand, there's much less to scan than in the former.
* Edit: as an example, compare the typical sub-10 character expression of Kadane's algorithm in an array language with the sub-10 line expressions one typically finds online.
APL people often point to the definition of "average" as evidence for its economy of expression: +/÷≢
They make the argument "the word 'average' has more symbols than its definition, so why not just use the definition inline as a tacit function?"
There's some elegant beauty in this that I'm sympathetic to. However, I think it's fundamentally flawed for one big reason, which in my opinion is the core of the unreadability of APL (and other array languages that rely on custom symbology):
Humans think in words, not letters. There is never semantic content in individual letters; a word is not defined by its letters. Sometimes a word's definition can be deduced from its syllables ("un-happi-ness") but the number of prefixes/suffixes is miniscule compared with the number of root words.
We naturally chunk concepts and create referential identifiers to the abstractions. The point of an alphabet is to make the identifiers generally pronounceable and distinguishable.
+/÷≢ is not pronounceable as a single word, even among APL experts ("add reduce divide tally" is not a word). We have a word for this concept in English, "average" (and synonyms "avg" and "mean"), in common usage among programmers and laymen alike. Using +/÷≢ to mean "average" would be like defining a function AddReduceDivideTally(x), which in any reasonable codebase would be an obviously bad function name.
The semantics of array languages, like stack languages, already lend themselves to extraordinary expressivity and terseness, even without a compressed symbology. What is wrong with this?
sum := add reduce
average := sum divide tally
I mean that is it, the essence of "average"! Anyone who knows both English and Computer Science can look at that and understand it more or less immediately. Compressing this into an esoteric alphabet does nothing for furthering understanding, it only creates a taller Tower of Babel to separate us from our goal of developing and sharing elegant definitions of computation concepts.
But using +/÷≢ to mean average isn't like using AddReduceDivideTally, it's like +/÷≢. With substantial array programming experience I do read this as a single word and pronounce it "average"; why should the fact that each symbol has its own meaning prevent me from processing them as a group? It's purely a benefit in that I can (more slowly) recognize something like +/÷⊢/⍤≢ as a variant of average, in this case to average each row of an array.
My opinion on the overall question, which I've written about at [0], is that it's very widely acknowledged that both symbols and words are useful in programming. This is why languages from PHP to Coq to PL/I all have built-in symbols for arithmetic, and usually a few other things, and built-in and user-defined words. The APL family adds symbols for array operations, and often function manipulation. Perhaps not for everyone, but, well, it's kind of weird to see a proof that a language I use to understand algorithms more deeply couldn't possibly do this!
In some languages, e.g. Chinese, each symbol means more than a single letter would in a latin alphabet. These languages to me are just a bit more like that.
That's true. Just a nitpick: it's not about letters, it's about things that make up a word, and many words in natural languages are made up of smaller parts that have meaning.
But people do tend to forget them and just use the resulting word as a unit
Can't think of a good example in English but in Italian the word "alarm" is "allarme" which comes from "alle armi !" (to the weapons!). At some point people used that word to mean you should grab your weapons and then later they just meant it metaphorically. Most people today don't even make the connection between these two words despite it being right in the face.
> +/÷≢ is not pronounceable as a single word, even among APL experts ("add reduce divide tally" is not a word
I’m not entirely certain most programs will ever be pronounced.
> What is wrong with this?
average := add reduce divide tally
Nothing, but but it seems to imply that this:
average := +/÷≢
… nicely resolves this issue of wanting to use words — AKA sequences of pronounceable but semantically meaningless glyphs —- as human-friendly (at least for English-fluent humans) mnemonics for programs — AKA sequences of not-muscle-memory-pronounceable but semantically meaningful glyphs), yeah?
Mind you I haven’t looked at the language deeply enough to know you can actually define an alias like that.
> If (and I grant, this is a big if) you are used to them, the symbolic nature of APLs allows to discuss code fragments (and even entire* algorithms) using inline elements instead of as separate interspersed blocks.
So I easily grant you this, though I don't think it's much different in practice than using subroutines.
But even if I grant you that a high level of experience allows rapid scanning, there's still a barrier of translating to and from English (or whatever language you develop in) that seems to be higher due to the symbolic nature of the language. This is also true with certain procedural languages, but there's also been an enormous number of think pieces about how best to encode procedural programs so that they do naturally translate into natural language domains. I'd imagine that not being able to leverage those decades of discussion straightforwardly would be a loss.
Granted, this is also a problem with stuff like Haskell too, but the type system goes a long way to ameliorating this concern by classifying structures very rigidly.
I think for most people the learning curve is steeper with tacit languages, mainly as you have to hold the stack/array state in your head.
Mathematicians will probably find it familiar, and as-per forth you could annotate with some sort of stack diagram for an aide memoire.
If you're looking for something more understandable, rebol syntax is phenomenal.
It's a concatenative prefixRL language like Uiua (forth is postfixLR), which you can use like a stack or array language by passing the stack/array as the far-right operand.
http://blog.hostilefork.com/rebol-vs-lisp-macros/
Furthermore it handles types and has (declarative) scoping unlike say forth which is typeless (panmorphic) and global.
The idea with rebol, similar to Joy, is that operations-on-a-stack is analagous to passing-mutable-stack-to-function so you get tacit programming with both approaches. PrefixRL allows more of a lispy feel, especially when combined with blocks.
Akshually APL can be considered more classical than algol-style languages, since it originated as mathematical notation for teaching programming on a blackboard in class.
Lisp beats APL by a few years though, so there it really depends on whether you value lisp's seniority or APL's connection to math notation traditions more when judging how "classical" a language syntax is.
Oh, you can touch type emoji and symbols today. There are all sorts of interesting Input Method Editors (IMEs) for them. Since Windows 10 there's one by default in Windows if you type Win+. or Win+; (whichever you prefer). You can type and it will filter the emoji by name. It's not quite as nice for mathematical symbol entry, but it does include them (on the tab labeled with an Omega) and is still better than many other input methods for them. macOS has a similar out-of-the-box IME (Control+Command+Space), though it differs on the amount of math symbol support. Linux's most used IME subsystem `ibus` (specifically `ibus-emoji`) if correctly setup should also by default provide an experience for emoji (Super+. like Windows). There are third-party ones as well for most platforms.
Emoji is not just for tap-typing/swipe-typing mobile users. (Also, I think it is really handy as developer to learn your local emoji IME: including emoji in test data is really handy for checking unicode safety in your applications and regularly using any IME at all while in your applications helps you test some accessibility issues that might affect users that must use an IME for there language such as CJK languages and Braille writers and more. English software developers get to overlook a lot of how languages around the world work and can easily break accessibility needs with bad assumptions and it is great that emoji are a grand field leveling tool to bring those experiences to us English speaking developers in a way we can easily "read"/"write".)
I meant "brevity at all costs" languages like J and Uiua strike me as the kind of contraptions that people who can't type fast would come up with. I speak from experience. I had a coworker who would write absolutely cryptic code and one day we were working together and I noticed he was typing painfully slow, and then it all clicked.
I'm well aware it's possible to type eg Chinese rapidly, and I use the Windows emoji entry keyboard quite often.
I see these languages as resembling classic mathematical notation as much or more than I see them as "lazy typist" languages. To be fair, some of classic mathematics notation was designed to be easy to write on blackboards, but that's still very different from being easy to type.
FWIW that's only the case for the website, in the local interpreter mode there appear to be specific functions for rendering a bunch of numbers as audio/images.
That surprised me too, but then I decided it was actually kinda brilliant. The alternative for when an array is "too big" to display is usually something like
[1 2 3 ... 99999]
Which is unsurprising, but not very usable. Audio is useful!
> The ^ above stands for the 3-dot cube dice glyph, which gets eaten by the HN backend, so it's ^ instead.
Just write "random" instead, then the snippet is copy-pasteable to the web-based interpreter. That's how you would normally write it out anyway, and interpreter will turn that into the dice glyph when run.
This is shows that you cannot make a language in the vacuum. There are other places and services that you need to integrate with and the use of these glyhps is making it harder.
I think using simple words: find, reverse, etc. is probably a better option.
Or it proves that HN's unicode stripping and intentional emoji blocking is making it harder than necessary to communicate some math and programming topics in their preferred notations.
(Also, this language supports the "simple words" approach but autoformats to the glyphs for final "readability".)
My recent exposure to array programming languages came via a podcast called The Array Cast[1]
Not affiliated, just recommending. The regular co-hosts appear to each be experienced with various array languages such as J, APL, etc. They don't get deeply technical, but it's a nice introduction, especially on explaining the appeal.
A recent episode had Rob Pike (UTF-8, Go, etc.) on to talk about his array based calculator, Ivy[2]
Our upcoming episode is an interview with Kai Schmidt, the creator of Uiua. It will be published this weekend. It turns out that Kai is a fan of the ArrayCast and it was his introduction into array programming.
They can be. I know J has libraries for databases, image, audio processing, etc.
I've written an assembler in J and translated it to K.
The array languages are pretty decent for prototyping machine learning stuff. Often you don't need any libraries at all.
Here's a 2-layer perceptron, first in Python+NumPy:
Dyalog APL is the one I'm most familiar with; as well as its array language syntax it has procedural-style keywords for control flow[1] like if/then/else and do/loop and so on. It has OOP class syntax too, and .NET framework bindings for event-driven Windows Forms GUIs and calling C#/.NET DLLs or building APL-based DLLs for other .NET languages. So yes, but you're not writing much array style code to do those parts. As well as being usable for the back end of a webserver.
array languages are used by several companies for their work. K for example is pretty popular in fintech. Some present companies provide services for array languages as well.
My favorite episodes were Stevan Apter, Leslie Goldsmith, Lib Gibson, Rob Pike and Jeremy Howard. If you want to go deep into the concepts focus on the tacit episodes or the ones with John Earnest or Aaron Hsu. There are transcripts with each episode so you can always read if your time is that valuable. https://www.arraycast.com/episodes
Did you mean generals of array languages? I've only listened to the first 3 episodes so far and the Rob Pike episode[1] I mentioned. I have decades of experience in the popular programming languages and Lisp and some functional languages, but I'm new to array languages and I think I am the target audience.
If you're already experienced with array languages I'm not confident to recommend any particular episodes yet. You might find the Rob Pike/Ivy episode entertaining but maybe not informative. Rob is not an array language expert (he says this in the episode) but he made Ivy partly from nostalgia of APL in his early days. His recollection of that era I found good to listen to.
Well this is neat. In an odd way it reminds me of how Assembly uses short commands, but instead of 1-4 letter cmdlets it's just symbols, but with many more arrays. It makes for a visually interesting codebase.
The thing that stands out the most to me is how the language itself functions as a work of art.
This does look quite nice. I always felt that the operator precedence / association rules in other stack languages were by far the most difficult thing to get used to, not the nonstandard symbols. This appears more inviting in that regard.
I do have to question the choice of right-to-left (array language) evaluation order. I've personally always preferred left-to-right (stack language) evaluation. I feel like right-to-left requires you to think to the end of a line before you start typing anything at all, as the first thing you type is the last thing that's evaluated. Left-to-right would also allow re-evaluating and visualizing the stack as you write each operator.
...Swap your language prefs to say, arabic? ;)
More seriously though, I think it depends what your background is. Maths works in prefix notation eg. f(g(x)) but I appreciate that you can hold the stack in your head easier with postfixLR.
Many people who are used to lisp would probably prefer prefix notation. non-stack or array langs have a nice tradeoff that you can look at the code without having to keep a model in your head, notably many forth users annotate their code with stack diagrams to help. Personally I'm quite taken with rebol syntax, passing a stack/array as the rightmost operand.
http://blog.hostilefork.com/rebol-vs-lisp-macros/
I like the use of non-ASCII Unicode glyphs and symbols for some functions/commands.
It makes me wonder why (since we now have rich graphical user interfaces as opposed to monochrome ASCII command-line dumb terminals that were prevalent in the mid-early history of computers) more languages don't support those.
On a related note, I think it would be interesting to research computer languages which were developed in base languages that are not English, i.e., any computer languages originating out of India, Russia, China, Japan, etc. -- to name a few...
Maybe there's such a thing as an Esperanto programming language...
Getting back to symbols though, a future society might implement a purely symbol based programming language.
Were ancient Egyptian hieroglyphs -- a programming language for a computing architecture that has vanished in the depths of time?
One can only speculate!
We do know that in our current day there are programming languages like Mathematica, where Math symbols can be used in lieu of English(y) code, and there may be a trend to more symbols replacing ASCII named/spelled keywords and functions in our code in languages of the future...
The use of symbols to replace words might result in smaller tighter, more readable code -- but (I'm thinking from the perspective of a future society here) it also might sever the bridge to computing's past...
Which may be desirable to have, IF that future society would want to resurrect computers and compuation from a future apocalyptic event...
But perhaps I'm thinking too hard about all of this...
Interested parties may want to check out the following video:
"Why are these 32 symbols found in caves all over Europe | Genevieve von Petzinger":
Speaking of ancient hieroglyphs, there is a long lineage of symbol-based languages and it is interesting to follow their ebb and flow over time: APL is one of the oldest languages, existing alongside contemporaries like COBOL. In the ancient mainframe era when everything was up for grabs and few things felt set in stone (including character encodings and the format of punch cards, and the sorts of keyboards used to punch those cards) APL was there trying to save punch card space (but not keyboard space, there were some huge APL-focused keyboards) by using a heavily math notation-influenced symbolic language.
Of course, as such things go, APL's appeal fell as the mainframe world settled on EBCDIC or ASCII (depending on if you were an IBM shop or not) as a "universal" character encoding and also as saving punch card space was less of a problem as other storage systems became more prominent.
Uiua seems a fun "emoji-native" take on "your grandmother's" APL. (BQN is generally cited as among the first "Unicode-native" in the APL family. Beyond the stack language changes as neither APL nor BQN are stack languages, Uiua swaps some niftier emoji-based choices for operators that feel fresher and less "ancient math hieroglyphics" and little bit more "texting your modern friend who in this case is a computer" hieroglyphics.)
It is a fun "emoji-native" take, but I think "fun" almost sells it short.
It feels like there really is something special about how the combination of all the little things make it more than the sum of its parts. On a language level therews a stack + absence of operator overloading + simple array model to make it easier to reason about. On an interface level there is word-based input with autoformatting, and a zero-install web-based interface with reminder tooltips and clickable links.
The examples are a lot easier for me to read through than with other array languages I've tried. And I've seriously tried both Dyalog and BQN! I think they're brilliant, but something just refuses to click in my brain for them.
BQN is also easier to get started. It's the only array language I ever tried because of that. Uiua seems to be inspired by BQN but it's also a stack-based language (BQN isn't).
> The main language that inspired Uiua is BQN. While I had heard about APL before, BQN was my first real exposure to the power of the array paradigm. I think the language is an astounding feat of engineering. Marshall is both a genius and a great communicator.
Think I would like Uiua more if it required a space between terms. It wouldn’t be quite as tacit but it would be easier to read and more flexible — you could have multi-symbol operators.
If we're using this comments section as an informal feedback page, +1 to that. My mental model of stack-based languages are imperative, and it's strange when lists of actions read in reverse order. I may as well write a preprocessor that switches terms from RTL to LTR, as well as stick to spelling out the full names of operators, and see how far I get before I see why the original author made these decisions.
So my biggest question is, what can I use this for? I get most languages start as fun hobby projects, but there must be some thought behind this concept right?
Some people really like the idea of concatenative languages. I think this is probably reasonably viewed as "research into making those actually usable", in addition to a fun hobby project.
Edit: I think I understand from the language tour. You're supposed to write the ascii names like `find` then running the program converts built-ins to glyphs.