Based on the one thing I remember in APL I'm guessing the first two characters are "sum over some data structure" and the data structure is what the next two mean. What does it mean entirely?
Yeah - IDK why it never makes it to these lists. R too. Matlab being 2D matrix first/default gets it right for me there. IK matrices trivially translate to arrays, still: find 2D to be extra expressive on human level, for zero price paid. I get it it's all the same to the cpu. 2D rows-columns rectangle of data being the simplest data structure both necessary and sufficient covering a 1) matrix 2) spreadsheet 3) SQL table 4) directed graph of nodes and edges. (in the past I've read someplace that lists are for pie eaters, but wouldn't know myself
APL and K are still pretty daunting, but I've recently been dabbling in Lil[1], which is something like a cross between K and Lua. I can fall back on regular procedural code when I need to, but I appreciate being able to do things like:
127 * sin (range sample_rate)*2*pi*freq_hz/sample_rate
This produces one second audio-clip of a "freq_hz" sine-wave, at the given sample-rate. The "range sample_rate" produces a list of integers from 0 to sample_rate, and all the other multiplications and divisions vectorise to apply to every item in the list. Even the "sin" operator transparently works on a list.
It also took me a little while to get used to the operator precedence (always right-to-left, no matter what), but it does indeed make expressions (and the compiler) simpler. The other thing that impresses me is being able to say:
maximum:if x > y x else y end
...without grouping symbols around the condition or the statements. Well, I guess "end" is kind of a grouping symbol, but the language feels very clean and concise and fluent.
At one time I briefly spent a bunch of time learning kdb/q. I remember one particular day when I wrote a non-trivial program and it worked first time. I was so shocked I thought I must have suffered some kind of brain aneurism or something.
if you don't mind me asking, do you also remember the day when you wrote some non-trivial program in any language and it "worked" the first time, whatever that means (i presume "correctly")? what was the language? are you sure you've made a full recovery from that shock as well?
on a serious note, APL (and, by proxy, its descendants) invented REPL (dubbed "dialogue approach") long before the people who coined "REPL" even came to be. When that happened, C lanugage wasn't around either. Fortran was, granted, and sure enough it "worked" every time. you didn't even have to try, just punch it up on a punchcard, stick it in, wait a while. done. flawless.
on a closing note: writing correct programs takes skill and happens in iterations. the faster you can iterate, the faster you can justify your money's worth. the less you type, the more you think. less code less bug.
What I mean by "worked" in this context is compiled/parsed[1] without error and had correct behaviour when executed.
I have been programming professionally for about 30 years at this point, so it has happened to me literally hundreds of times at this point in at least 10 other languages- in fact in some languages (especially Haskell and Rust) I would say it's the norm for me rather than the exception to have the code work correctly if it passes compilation (which is sort of the point of strict type systems obviously).
It literally only ever happened the one time in kdb which is why I remember it so vividly and not in those other languages.
I have no idea why you thought your closing note might help, but sure.
Perhaps a more precise question is whether you can write programs as performant as those written in C or Fortran and the answer is it depends on the program (and more likely the programmer). The languages tend to do memory management for you which means giving up some control. Most use “immutable” data structures which force more contraints.
But for the loss of control you get stuff like fancy SIMD implementation for nothing.
All and all there’s a cost/benefit calculation but that ratio can get quite low.
I assume that in most array languages, you also create "words" or however you want to call functions, to reuse code. I wonder about a purely aesthetic issue: how does it look to interleave those symbols with user-defined words that by nature will be much, much longer, i.e. "create-log-entry" or "calculate-estimated-revenue".
> i assume that in most array languages, you also create "words" or however you want to call functions, to reuse code.
sure, that's a very useful feature, like elsewhere.
> I wonder about a purely aesthetic issue: how does it look to interleave those symbols with user-defined words that by nature will be much, much longer, i.e. "create-log-entry" or "calculate-estimated-revenue".
strictly speaking, dashes and underscores in k can't even be a part of identifier - they are core language primitives. it is very uncommon to see java-like identifiers like CalculateEstimatedRevenue, why would you want that?
to your question:
here's a bit of an oddity: all user-defined functions and core language operators can be called using functional notation:
v:1 2 3 / some vector
v+v / usual infix notation, two operands: left and right
2 4 6
+[v;v] / same as infix, but called as it were a function.
2 4 6
add:{x+y} / a user-defined function: a lambda with a name and two operands.
add[v;v]
2 4 6
but there is an important distinction between the two. you can't use your `add` function infix, you must call it as a function, and there are good reasons for that:
2 add 2 / that's not gonna work
that said, mixing language primitives with function calls looks and reads just fine:
33 comments
[ 3.0 ms ] story [ 66.7 ms ] threadwhat does he do these days?
+/%#
to people. But the real expressive power comes when you start to get into tacit expressions yourself, understand function exponents, and "get" under.
Hmmm... maybe I need a refresher...
Based on the one thing I remember in APL I'm guessing the first two characters are "sum over some data structure" and the data structure is what the next two mean. What does it mean entirely?
Also missing Uiua.
It also took me a little while to get used to the operator precedence (always right-to-left, no matter what), but it does indeed make expressions (and the compiler) simpler. The other thing that impresses me is being able to say:
...without grouping symbols around the condition or the statements. Well, I guess "end" is kind of a grouping symbol, but the language feels very clean and concise and fluent.[1]: https://beyondloom.com/decker/lil.html
r/apljk on reddit is also active.
never seems to make these lists :)
if you don't mind me asking, do you also remember the day when you wrote some non-trivial program in any language and it "worked" the first time, whatever that means (i presume "correctly")? what was the language? are you sure you've made a full recovery from that shock as well?
on a serious note, APL (and, by proxy, its descendants) invented REPL (dubbed "dialogue approach") long before the people who coined "REPL" even came to be. When that happened, C lanugage wasn't around either. Fortran was, granted, and sure enough it "worked" every time. you didn't even have to try, just punch it up on a punchcard, stick it in, wait a while. done. flawless.
on a closing note: writing correct programs takes skill and happens in iterations. the faster you can iterate, the faster you can justify your money's worth. the less you type, the more you think. less code less bug.
does that help?
I have been programming professionally for about 30 years at this point, so it has happened to me literally hundreds of times at this point in at least 10 other languages- in fact in some languages (especially Haskell and Rust) I would say it's the norm for me rather than the exception to have the code work correctly if it passes compilation (which is sort of the point of strict type systems obviously).
It literally only ever happened the one time in kdb which is why I remember it so vividly and not in those other languages.
I have no idea why you thought your closing note might help, but sure.
[1] Depending on language obviously.
if you don't mind sharing: how did your own first working program felt like, and what was it written in?
by the way, did it work, or did it work correctly? it's a small but important distinction.
But for the loss of control you get stuff like fancy SIMD implementation for nothing.
All and all there’s a cost/benefit calculation but that ratio can get quite low.
sure, that's a very useful feature, like elsewhere.
> I wonder about a purely aesthetic issue: how does it look to interleave those symbols with user-defined words that by nature will be much, much longer, i.e. "create-log-entry" or "calculate-estimated-revenue".
strictly speaking, dashes and underscores in k can't even be a part of identifier - they are core language primitives. it is very uncommon to see java-like identifiers like CalculateEstimatedRevenue, why would you want that?
to your question:
here's a bit of an oddity: all user-defined functions and core language operators can be called using functional notation:
but there is an important distinction between the two. you can't use your `add` function infix, you must call it as a function, and there are good reasons for that: that said, mixing language primitives with function calls looks and reads just fine: hope this helps!or here:
https://xpqz.github.io/kbook
coming from javascript world this is super interesting, i will try and document some of the stuff i learn on that site is well.