Hacker News new | ask | show | jobs
by zerker2000 2134 days ago
I've always been curious one decision pervading various APL: what are the relative merits of right to left evaluation order, vs more conventional left-to-right method chains? The core principles are incredibly elegant, but I must admit hitting "expressions are executed right to left, except if you hit a {} lambda, wherein separate statements are ordered left to right, but are themselves expressions going right to left again" is always kind of jarring.
2 comments

For left-to-right execution, the dissonance between execution and statement separators (including functions and list notation) is very bad as you note.[0] For right-to-left execution, assignment has a similar problem: the name really needs to be on the left to allow easily scanning definitions, but this conflicts with the evaluation order. Particularly statements with multiple assignments in them don't work at all. Right-to-left is usually framed as a more "declarative" or "functional" style (and note that application and composition of mathematical functions follows this order) while left-to-right is considered "imperative".

In my first major language, I,[1] I did change to a left-to-right order. For BQN, which is intended to stick much closer to traditional APL, I didn't want to make such a large break from the methods that have worked in the past. I do think I'll introduce some mechanism like a "pipe" that goes in statement order so that longer chains of functions and operators can be built up without such a discontinuous reading order.

[0] https://mlochbaum.github.io/BQN/problems.html#right-to-left-...

[1] https://github.com/mlochbaum/ILanguage

> Parentheses may be used to specify the order, but there's a (usually) better way as well: whitespace! Fewer spaces means the function will be executed earlier.

Oh man, that is a fascinating idea I've played around with some, glad someone's put it more seriously into practice.

Re: assignments, Aaron sure seems to sprinkle them liberally inside lines - though not generally ones referenced in subsequent ones, to be fair. (I suppose another notable attribute of the co-dfns codebase is extensive use of ⊣ as a leftwards statement separator)

Mathematical functions are prefix, which imo is much harder to follow than either infix (OO/APL) or suffix (RPN/Forth), though this may be more of an english-speaking intuition than some manner of universal truth. I do at least observe a trend towards "imperative but functionally pure / side-effect isolated" in recent language design.

Ah, I see ILang deals with the issue by… not having a name binding primitive, making you SKI-calculus your arguments into place. (Compare the piles of roll-swap-dup you get in varless forth dialects, though not as bad due to there being two directions args are passed in from.)

I suspect there is room here for an unprincipled "preceding word/pattern is defined by the following line/s" loose-binding operator, to restore skimability, and a separate inline destructuring let form that cannot leak out of lexical scope. Which I suppose would warrant lambdas - perhaps with ⍺ ⍺⍺ ⍺⍺⍺ to denote enclosing function input, rather than argument/operand/hyperand, though nonconcrete functions would stress the type system as is

It does have : for assignment, although there's no scoping, and you have to assign to symbols that are surrounded in single quotes. You can see some examples at https://github.com/mlochbaum/ILanguage/blob/master/examples/... . They need extra parens, since : is an ordinary function and has the symbol on the left. Your overall point is right; I didn't really try to address any issues with assignment. And of course there are lots of things to try, and I hope some of them make it into some other language I design!
I think it's history: in the 1960's, machines were strongly card (or at least line) oriented, so pure right to left intracard yields a very small "parser" compatible with traditional mathematical notation, and the unavoidable intercard transitions become top to bottom on a teletype.

(FWIW in my array noodling, the equivalent of dfns are given in the haskell style of "expr where defs" instead of the strictly temporal "let defs in expr", which does result in a consistent right to left for those who wish to read bottom-up.)