If f is one function, argument one int, result one int... What happen when that function is called to one list of ints? f 1 2 3 is the list (f 1),(f 2),(f 3)? If that is true what is the difference for f¨1 2 3?
@RosLuP If f is entirely defined in terms of scalar functions, then yes, f 1 2 3 will be the same as (f 1),(f 2),(f 3) and f¨1 2 3, but if the function has side-effects, then note that (f 1),(f 2),(f 3) processes 3 first, while f 1 2 3 processes all three at once, and f¨ 1 2 3 processes 1 first:
@Adám Oh I did stare at it for some time... and with some bad conscience ignored most of it. I just added more test cases, compared to tryapl and patched...
@RosLuP Yes, as you correctly concluded, functions are always passed their entire arguments. However, you can of course control that with ¨ or ⍤, but again, the derived function f¨ or f⍤k is of course still passed the entire argument.
@ktye I've had to ask our CTO about it a few times.
The problem born for the function 1π that here would find the next prime... If 1π1 2 3 here is ok it is probably because they define 1π function for list and scalar, but if one not know this it has to be 1π¨ 1 2 3
@RosLuP For the prime finding function it is even more important that the function handles such, so it avoids doubling work. Clearly, it has to find the largest scalar in its argument, then find only primes up to that number, and the lower ones are included there.
@ktye (x;y;) syntax, ranks ≤1, fns as 1st-class objects, no parsing ambiguity (you can tell apart verbs from nouns at parse time) - so, this is more k than apl :)
yes, the K influence came later, when I read about it. Separating parsing from evaluation felt easier. User defined operators does not exist. If I want to add it, I need special variable names. I thought about greek letters, or a prefix.
@ngn There is more from K: time/date, dicts and tables
@ktye no, i'm a hobbyist, i don't make money from k. at this stage i don't see what i would gain from publishing it - most people i've talked to simply don't appreciate the significance of a small fast half-apl half-lisp. also, my source looks horrible
@ngn Neither does the code after. In this case. I was just illustrating the general pattern. However, if you need several branches there too, then it does need to be.
@ngn No, I meant that the middle dfn takes over after all the branches of the before dfn, and the after dfn takes over after all the branches before it.
@ngn They sure would have been more versatile if they would continue after a guard if the expression after : was an assignment. But where should they continue? With the very next statement?
@ktye Also consider continuing after an unguarded dfn expression, even if there is not assignment. E.g. {2 ⋄ 3} should return 3, not 2.
@ktye That's the reason for "big APLs"' quirks: Backwards compatibility.
I find it pretty cool that most half-century old APL code can run in modern interpreters with no modification, and if anything needs to be changed, it is trivial.
@ktye i can relate :) but i think you should be careful - early design decisions tend to have profound consequences if/when your language becomes popular
@ngn There is also a not so simple version cmd/lui, that contains a graphical user interface, a sam text editor and a virtual file system. But it's very recent.
That's good for you. I work on windows and at work the files have too long names. That's why I wrote the per-session file system. In apl I mount the current working directory to root with /m./
Actually I have 3 ways to parse strings: 'abc' => same as apl results in a vector containing 3 strings "a" "b" "c" "abc" => a single string (atom) `abc => short form
` does not end when an apl symbol starts. I did it because I want to be able to write paths like that `/file/to/path
@Adám This creates a dict. The syntax is very similar to K's
@ktye Oh, so because you don't support generalised nested arrays, you repurposed ⊂ to create a symbol from a charvec (and I presume ⊃ for the opposite).
String is not atom or scalar... It is list... Scalar is 'a' only but ,'a' seems vector even if it print as scalar... There would be need one function for display the type...
@RosLuP In regular APL, sure. But ktye has made his own, with some influences from Go and K.
@RosLuP Most major APLs have some incarnation of the traditional DISPLAY function, and Dyalog also ships a tool, ⎕SE.Dyalog.Utils.repObj with will give you an expression that evaluates to the argument.
it's not like that by design. It's just not bug-free. There are more issues when using operators that copy anything that is not a pure number.
what should an implementation of a primitive function assume? Can it modify it's input argument (that the caller has to copy), or should it copy if it modifies?
@ktye sure. it's important to get the design right. bugs are bugs and ultimately get fixed. well, unless you're locked into perpetual backwards compatibility, hehe :)
@ktye that's probably the hardest part of implementing efficient array languages - refcounting
@ktye well, if you can figure out a more efficient way to do it, that would be most awesome, but what most impls do is maintain a "reference count" for each object - a counter for how many other objects point to it
when you create a pointer to something, you increment its refcount. when you destroy a pointer, you decrement it and free() it if it's dropped to 0
when amending an object, for instance with a[i]+←b you can reuse a's memory as along as its refcount is 1 (or 0, depending on how you count)
@ktye instant gc is one of the uses of refcounting
ideally, your object graph mustn't contain loops
(terminology note: by "garbage collection" many people mean "mark-and-sweep garbage collection". they don't consider "refcounting" to be "garbage collection")
@ngn I think you're being way too harsh on Dyalog. Pass-by-ref is sensible for OO, and OO-based GUI. It it wasn't for ⎕WC (which grew into today's Dyalog OO), there would be no Dyalog today, and APL would probably be all dead and forgotten too.
@ngn Of course, of course. We all agree that that OO is nasty, but it saved APL's skin. You probably wouldn't even have known about APL if it wasn't for those ref cycles!
@ngn and having pass-by-reference is a nice way to do that
completely hypothetical syntax - e.g. w ← ⎕newWindow⍬ ⋄ b ← ⎕newButton⍬ ⋄ w.add b ⋄ b.setText 'hi' ⋄ ⎕openWindow w wouldn't work, as b was modified after it's been added to the window, which imo isn't nice
if i wanted to change the buttons text later I'd either have to have told w.add some reference name just so i'd be able to do w.b.setText '...' (which feels like just trying to get around the issue of no references), or recreate the whole structure from scratch (which is horribly inefficient)
@ngn IMO passing variables by string representation of name is just very very horrible and very much trying to force around the problem of no references, but that's just my opinion
what if I wanted to create n buttons? would I have to dynamically create n different variables?
it also allows me to delete the variable dict before it's properly used, which forces the drawing mechanism to do non-existence checks everywhere, while it could just have them at the adding time
for an immutable-dict-based GUI it'd be quite a challenge to make ⎕draw w not redraw the whole window & everything every time but just the parts that have changed too, while a ref-based one wouldn't even have to touch the whole window object when a buttons text has changed
@ktye well, if you're comfortable with mutability, you could just do nothing. if you insist on value semantics (like me), you could always make a copy of the dict for now, and worry about implementing your own refcounting later
For dicts and tables, the plan was value semantics. Current behaviour is a bug. But I have references also, when dealing with pointers to go structs, e.g. The definition of the type can decide, what it should be.
@dzaima You have to keep them in sync. I like it how they represent a single row of a table. I plan to use dicts to build property dialogs in a user interface, and tables to keep a list of those.
@dzaima what ktye said, and they are also used to represent the "k-tree" - a hierarchical structure of contexts in which variables/functions live. you can write a.b.c to access a path in that tree, equivalent to a[`b][`c] or a[`b;`c] or (if dicts were just pairs of lists) some complicated expression involving x?y and x@y lookups (⍺⍳⍵ and ⍵⊃⍺ in apl)